diff --git a/.agents/AGENTS.md b/.agents/AGENTS.md index aae3e37..866f06d 100644 --- a/.agents/AGENTS.md +++ b/.agents/AGENTS.md @@ -122,8 +122,11 @@ ## ๐Ÿ” ๊ทผ๋ณธ์›์ธ ๋จผ์ €, ๋•œ๋นต ๊ธˆ์ง€ - ์ฆ์ƒ์„ ๊ฐ€๋ฆฌ๋Š” ๋•œ๋นต์šฉ ์ฝ”๋”ฉ์€ ์ง€์–‘ํ•ฉ๋‹ˆ๋‹ค. **ํ•ญ์ƒ ๊ทผ๋ณธ์›์ธ์„ ๋จผ์ € ์ฐพ๊ณ ** ์ดˆ๋“ฑํ•™์ƒ๋„ ์ดํ•ดํ•˜๊ธฐ ์‰ฝ๊ฒŒ ์„ค๋ช… ํ›„ ์„ค๊ณ„ํ•˜๊ณ  ๋ณด๊ณ ํ•ฉ๋‹ˆ๋‹ค. +- **๋ฒ„๊ทธ ๋ฐœ๊ฒฌ ์‹œ ํ•ด๋‹น ํ•จ์ˆ˜๋ฅผ ๋”ฐ๋ผ๊ฐ€ ๋ฉด๋ฐ€ํžˆ ๋ถ„์„ ํ›„ ์„ธ ๊ฐ€์ง€ ๊ทผ๋ณธ์ ์ธ ๋Œ€์•ˆ์„ ์ œ์‹œํ•˜๋„๋ก ํ•ฉ๋‹ˆ๋‹ค.** +- **์ถ”์ธก์„ฑ ๋Œ€์•ˆ์„ ์ œ์‹œํ•˜์ง€ ๋ง๊ณ , ์ฝ”๋“œ๋ฅผ ๊ตฌ์„๊ตฌ์„ ๋ฉด๋ฐ€ํžˆ ๋ถ„์„ํ•œ ํ›„์— ์ง„ํ–‰ํ•˜์„ธ์š”.** - "์ผ๋‹จ ์žฌ์‹œ๋„ยท์žฌ๋ฐœ๊ธ‰ยท๋ด‰์ˆ˜ ๋Š˜๋ฆฌ๊ธฐยทยฑ1 ๋ณด์ •"์œผ๋กœ ์ฆ์ƒ๋งŒ ๊ฐ€๋ฆฌ๊ธฐ ๊ธˆ์ง€. - API ๊ด€๋ จ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑ/์ˆ˜์ •ํ•  ๋•Œ๋Š” ๋ณธ์ธ์˜ ์ง€์‹์— ์˜์กดํ•˜์ง€ ๋ง๊ณ  **๋ฐ˜๋“œ์‹œ ์—ฐ๋™๋œ MCP ๋„๊ตฌ๋ฅผ ์šฐ์„  ํ˜ธ์ถœ**ํ•˜์—ฌ ์ŠคํŽ™์„ ํ™•์ธํ•˜์„ธ์š”. +- **์‹œ๊ฐ„์ด ์˜ค๋ž˜ ๊ฑธ๋ ค๋„ ์ข‹์œผ๋‹ˆ ๋ถˆํ•„์š”ํ•˜๊ฒŒ ํ† ํฐ์„ ๋‚ญ๋น„ํ•˜์ง€ ๋ง๊ณ , ๋๊นŒ์ง€ ๋”ฅ๋‹ค์ด๋ธŒํ•˜์—ฌ ๊ทผ๋ณธ์ ์ธ ์›์ธ์„ ์ฐพ์•„๋‚ด์–ด ํ•ด๊ฒฐํ•˜์„ธ์š”.** --- diff --git a/anti_cli_chat b/anti_cli_chat new file mode 120000 index 0000000..6e276c7 --- /dev/null +++ b/anti_cli_chat @@ -0,0 +1 @@ +/home/hoon/.gemini/antigravity-cli/brain/ \ No newline at end of file diff --git a/data/ticks/KR/20260831.parquet b/data/ticks/KR/20260831.parquet new file mode 100644 index 0000000..4c5de96 Binary files /dev/null and b/data/ticks/KR/20260831.parquet differ diff --git a/data/ticks/KR/20260901.parquet b/data/ticks/KR/20260901.parquet new file mode 100644 index 0000000..6d683de Binary files /dev/null and b/data/ticks/KR/20260901.parquet differ diff --git a/data/ticks/KR/20260902.parquet b/data/ticks/KR/20260902.parquet new file mode 100644 index 0000000..ae23f8f Binary files /dev/null and b/data/ticks/KR/20260902.parquet differ diff --git a/data/ticks/KR/20260903.parquet b/data/ticks/KR/20260903.parquet new file mode 100644 index 0000000..fd2dd48 Binary files /dev/null and b/data/ticks/KR/20260903.parquet differ diff --git a/data/ticks/KR/20260904.parquet b/data/ticks/KR/20260904.parquet new file mode 100644 index 0000000..e5ccc95 Binary files /dev/null and b/data/ticks/KR/20260904.parquet differ diff --git a/kis_rust_core.so b/kis_rust_core.so new file mode 100755 index 0000000..7ac01be Binary files /dev/null and b/kis_rust_core.so differ diff --git a/kis_rust_core/src/lib.rs b/kis_rust_core/src/lib.rs deleted file mode 100644 index 353aa91..0000000 --- a/kis_rust_core/src/lib.rs +++ /dev/null @@ -1,28 +0,0 @@ -use pyo3::prelude::*; - -pub mod tail; -pub mod db_loader; -pub mod scalp; - -/// ํŒŒ์ด์ฌ์—์„œ ํ˜ธ์ถœํ•  ๋ฐฑํ…Œ์ŠคํŠธ ๋ฒค์น˜๋งˆํฌ ํ•จ์ˆ˜ -#[pyfunction] -fn run_dummy_backtest(params: &str) -> PyResult { - // ์‹ค์ œ๋กœ๋Š” ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ํŒŒ์‹ฑํ•˜๊ณ  ๋ฃจํ”„๋ฅผ ๋Œ์•„์•ผ ํ•˜์ง€๋งŒ, ์ง€๊ธˆ์€ ์—ฐ๊ฒฐ ํ…Œ์ŠคํŠธ์šฉ - println!("[Rust] ํŒŒ์ด์ฌ์œผ๋กœ๋ถ€ํ„ฐ ๋ฐ›์€ ํŒŒ๋ผ๋ฏธํ„ฐ: {}", params); - let dummy_pnl = 150000.0; // 15๋งŒ์› - Ok(dummy_pnl) -} - -/// ๋ชจ๋“ˆ ์ดˆ๊ธฐํ™” -#[pymodule] -fn kis_rust_core(_py: Python, m: &PyModule) -> PyResult<()> { - m.add_function(wrap_pyfunction!(run_dummy_backtest, m)?)?; - m.add_function(wrap_pyfunction!(tail::run_tail_backtest_fast, m)?)?; - m.add_function(wrap_pyfunction!(db_loader::load_candles_from_db, m)?)?; - m.add_function(wrap_pyfunction!(scalp::run_scalp_backtest_fast, m)?)?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - Ok(()) -} diff --git a/kis_rust_core/src/tail.rs b/kis_rust_core/src/tail.rs deleted file mode 100644 index 0ea6466..0000000 --- a/kis_rust_core/src/tail.rs +++ /dev/null @@ -1,97 +0,0 @@ -use pyo3::prelude::*; -use serde::{Deserialize, Serialize}; - -#[pyclass] -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct TailParams { - #[pyo3(get, set)] - pub rsi_limit: f64, - #[pyo3(get, set)] - pub drop_pct_min: f64, - #[pyo3(get, set)] - pub tail_recovery_min: f64, - #[pyo3(get, set)] - pub target_pct: f64, - #[pyo3(get, set)] - pub stop_loss_pct: f64, -} - -#[pymethods] -impl TailParams { - #[new] - pub fn new(rsi_limit: f64, drop_pct_min: f64, tail_recovery_min: f64, target_pct: f64, stop_loss_pct: f64) -> Self { - Self { - rsi_limit, - drop_pct_min, - tail_recovery_min, - target_pct, - stop_loss_pct, - } - } -} - -/// ๊ผฌ๋ฆฌ์žก๊ธฐ์šฉ ์บ”๋“ค ์ •๋ณด (๊ฐ„์†Œํ™”) -#[pyclass] -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct CandleData { - #[pyo3(get, set)] - pub time_str: String, - #[pyo3(get, set)] - pub open: f64, - #[pyo3(get, set)] - pub high: f64, - #[pyo3(get, set)] - pub low: f64, - #[pyo3(get, set)] - pub close: f64, - #[pyo3(get, set)] - pub volume: f64, - #[pyo3(get, set)] - pub rsi: f64, -} - -#[pymethods] -impl CandleData { - #[new] - pub fn new(time_str: String, open: f64, high: f64, low: f64, close: f64, volume: f64, rsi: f64) -> Self { - Self { time_str, open, high, low, close, volume, rsi } - } -} - -/// ๋‹จ์ผ ์ข…๋ชฉ ๋ฐฑํ…Œ์ŠคํŠธ ์‹œ๋ฎฌ๋ ˆ์ดํ„ฐ (๊ผฌ๋ฆฌ์žก๊ธฐ) -#[pyfunction] -pub fn run_tail_backtest_fast(params: &TailParams, candles: Vec) -> PyResult { - let mut pnl = 0.0; - let mut in_position = false; - let mut entry_price = 0.0; - - for candle in candles { - if !in_position { - // ์ง„์ž… ๋กœ์ง: ํ•˜๋ฝ ํ›„ ๊ผฌ๋ฆฌ ํšŒ๋ณต (๋‹จ์ˆœํ™”๋œ ํœฉ์˜ ํ‰๋‚ด) - let drop = (candle.low - candle.open) / candle.open * 100.0; - let recovery = (candle.close - candle.low) / candle.open * 100.0; - - if candle.rsi < params.rsi_limit - && drop <= -params.drop_pct_min - && recovery >= params.tail_recovery_min - { - in_position = true; - entry_price = candle.close; - } - } else { - // ์ฒญ์‚ฐ ๋กœ์ง - let profit_pct = (candle.high - entry_price) / entry_price * 100.0; - let loss_pct = (candle.low - entry_price) / entry_price * 100.0; - - if profit_pct >= params.target_pct { - pnl += entry_price * (params.target_pct / 100.0); - in_position = false; - } else if loss_pct <= -params.stop_loss_pct { - pnl += entry_price * (-params.stop_loss_pct / 100.0); - in_position = false; - } - } - } - - Ok(pnl) -} diff --git a/kis_rust_core/.gitignore b/kis_rust_src/.gitignore similarity index 100% rename from kis_rust_core/.gitignore rename to kis_rust_src/.gitignore diff --git a/kis_rust_core/Cargo.toml b/kis_rust_src/Cargo.toml similarity index 73% rename from kis_rust_core/Cargo.toml rename to kis_rust_src/Cargo.toml index 7d1af4b..7840177 100644 --- a/kis_rust_core/Cargo.toml +++ b/kis_rust_src/Cargo.toml @@ -8,7 +8,12 @@ name = "kis_rust_core" crate-type = ["cdylib"] [dependencies] +lazy_static = "1.5.0" pyo3 = { version = "0.20.0", features = ["extension-module"] } serde = { version = "1.0", features = ["derive"] } sqlx = { version = "0.7", features = ["mysql", "runtime-tokio-rustls"] } tokio = { version = "1", features = ["full"] } +rayon = "1.8" +serde_json = "1.0" +polars = { version = "0.55.2", features = ["parquet", "lazy"] } +chrono = "0.4.45" diff --git a/kis_rust_src/src/breakout.rs b/kis_rust_src/src/breakout.rs new file mode 100644 index 0000000..3b7588c --- /dev/null +++ b/kis_rust_src/src/breakout.rs @@ -0,0 +1,547 @@ +use pyo3::prelude::*; +use serde::{Deserialize, Serialize}; +use rayon::prelude::*; +use crate::tail::CandleData; + +#[pyclass] +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct BreakoutParams { + #[pyo3(get, set)] + pub lookback_min: usize, + #[pyo3(get, set)] + pub vol_window: usize, + #[pyo3(get, set)] + pub vol_mult: f64, + #[pyo3(get, set)] + pub prev_chg_min: f64, + #[pyo3(get, set)] + pub prev_chg_max: f64, + #[pyo3(get, set)] + pub max_daily_chg: f64, + #[pyo3(get, set)] + pub min_price: f64, + #[pyo3(get, set)] + pub min_bar_trade_value_krw: f64, + #[pyo3(get, set)] + pub min_turnover_1m_pct: f64, + #[pyo3(get, set)] + pub share_denom: f64, + #[pyo3(get, set)] + pub confirm_margin_pct: f64, + #[pyo3(get, set)] + pub body_min_pct: f64, + #[pyo3(get, set)] + pub use_ema_filter: bool, + #[pyo3(get, set)] + pub ema_fast_period: usize, + #[pyo3(get, set)] + pub ema_slow_period: usize, + #[pyo3(get, set)] + pub time_start_hm: usize, + #[pyo3(get, set)] + pub time_end_hm: usize, + #[pyo3(get, set)] + pub sl_pct: f64, + #[pyo3(get, set)] + pub tp_pct: f64, + #[pyo3(get, set)] + pub trail_pct: f64, + #[pyo3(get, set)] + pub trail_arm_pct: f64, + #[pyo3(get, set)] + pub shoulder_min_high: f64, + #[pyo3(get, set)] + pub shoulder_cut_pct: f64, + #[pyo3(get, set)] + pub max_hold_bars: usize, + #[pyo3(get, set)] + pub cooldown_min: f64, + #[pyo3(get, set)] + pub max_daily: usize, + #[pyo3(get, set)] + pub skip_hts_scan_dupes: bool, + #[pyo3(get, set)] + pub atr_period: usize, // ATR ๋™์  ์†์ ˆ์„ ์œ„ํ•œ ํ•„๋“œ +} + +#[pymethods] +impl BreakoutParams { + #[new] + #[allow(clippy::too_many_arguments)] + pub fn new( + lookback_min: usize, vol_window: usize, vol_mult: f64, prev_chg_min: f64, prev_chg_max: f64, + max_daily_chg: f64, min_price: f64, min_bar_trade_value_krw: f64, min_turnover_1m_pct: f64, + share_denom: f64, confirm_margin_pct: f64, body_min_pct: f64, use_ema_filter: bool, + ema_fast_period: usize, ema_slow_period: usize, time_start_hm: usize, time_end_hm: usize, + sl_pct: f64, tp_pct: f64, trail_pct: f64, trail_arm_pct: f64, shoulder_min_high: f64, + shoulder_cut_pct: f64, max_hold_bars: usize, cooldown_min: f64, max_daily: usize, skip_hts_scan_dupes: bool, + atr_period: usize + ) -> Self { + Self { + lookback_min, vol_window, vol_mult, prev_chg_min, prev_chg_max, max_daily_chg, min_price, + min_bar_trade_value_krw, min_turnover_1m_pct, share_denom, confirm_margin_pct, body_min_pct, + use_ema_filter, ema_fast_period, ema_slow_period, time_start_hm, time_end_hm, sl_pct, tp_pct, + trail_pct, trail_arm_pct, shoulder_min_high, shoulder_cut_pct, max_hold_bars, cooldown_min, + max_daily, skip_hts_scan_dupes, atr_period + } + } +} + +#[pyclass] +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct BreakoutTrade { + #[pyo3(get, set)] + pub code: String, + #[pyo3(get, set)] + pub buy_time: String, + #[pyo3(get, set)] + pub sell_time: String, + #[pyo3(get, set)] + pub buy_price: f64, + #[pyo3(get, set)] + pub sell_price: f64, + #[pyo3(get, set)] + pub pnl_pct: f64, + #[pyo3(get, set)] + pub reason: String, + #[pyo3(get, set)] + pub resistance: f64, + #[pyo3(get, set)] + pub vol_ratio: f64, + #[pyo3(get, set)] + pub prev_chg: f64, + #[pyo3(get, set)] + pub atr_entry: f64, + #[pyo3(get, set)] + pub max_price: f64, // ์ถ”๊ฐ€ +} + +fn parse_hm(time_str: &str) -> usize { + if time_str.len() >= 12 { time_str[8..12].parse::().unwrap_or(0) } else { 0 } +} + +fn parse_mins(time_str: &str) -> i64 { + if time_str.len() >= 12 { + let h = time_str[8..10].parse::().unwrap_or(0); + let m = time_str[10..12].parse::().unwrap_or(0); + h * 60 + m + } else { 0 } +} + +/// ๋‹จ์ˆœ ATR ๊ณ„์‚ฐ (Wilder's RMA ๋ฐฉ์‹) +fn compute_atr(candles: &[CandleData], period: usize) -> Vec { + let mut atrs = vec![0.0; candles.len()]; + if candles.len() <= period || period == 0 { return atrs; } + + let mut sum_tr = 0.0; + for i in 1..=period { + let h = candles[i].high; + let l = candles[i].low; + let pc = candles[i-1].close; + let tr = (h - l).max((h - pc).abs()).max((l - pc).abs()); + sum_tr += tr; + } + let mut atr = sum_tr / period as f64; + atrs[period] = atr; + + for i in (period + 1)..candles.len() { + let h = candles[i].high; + let l = candles[i].low; + let pc = candles[i-1].close; + let tr = (h - l).max((h - pc).abs()).max((l - pc).abs()); + atr = (atr * (period - 1) as f64 + tr) / period as f64; + atrs[i] = atr; + } + atrs +} + +#[pyfunction] +pub fn run_breakout_backtest_fast( + target_code: &str, + candles: Vec, + params: &BreakoutParams, +) -> PyResult> { + let mut trades = Vec::new(); + let mut in_position = false; + let mut buy_price = 0.0; + let mut buy_time = String::new(); + let mut resistance_entry = 0.0; + let mut vol_ratio_entry = 0.0; + let mut prev_chg_entry = 0.0; + let mut max_price_in_trade = 0.0; + let mut hold_bars = 0; + let mut atr_entry = 0.0; + + let mut daily_cnt = 0; + let mut cur_day = String::new(); + let mut last_exit_mins = -999; + + let mut running_open = 0.0; + let mut running_high = 0.0; + let mut running_low = 0.0; + + let atrs = compute_atr(&candles, params.atr_period); + + let need_len = if params.skip_hts_scan_dupes { 1 } else { params.lookback_min.max(params.vol_window) + 2 }; + + for i in need_len..candles.len() { + let c = &candles[i]; + let day = if c.time_str.len() >= 8 { &c.time_str[0..8] } else { "" }; + let hm = parse_hm(&c.time_str); + + if cur_day != day { + cur_day = day.to_string(); + daily_cnt = 0; + last_exit_mins = -999; + running_open = c.open; + running_high = c.high; + running_low = c.low; + } else { + if c.high > running_high { running_high = c.high; } + if c.low < running_low { running_low = c.low; } + } + + let current_mins = parse_mins(&c.time_str); + + if in_position { + hold_bars += 1; + if c.high > max_price_in_trade { max_price_in_trade = c.high; } + + let is_eod = hm >= 1520 && hm <= 1530 && c.time_str.ends_with("1520"); + + // ๋งค๋„ ๋กœ์ง (Breakout) + let mut exit_reason = ""; + let mut exit_price = 0.0; + + // ์†์ ˆ์„  (๊ณ ์ •%๋งŒ ์ง€์›, ATR ์ œ์™ธ ๊ฐ„๋žตํ™”) + let sl_line = buy_price * (1.0 - params.sl_pct); + let tp_line = buy_price * (1.0 + params.tp_pct); + + if is_eod || hm >= 1530 { + exit_reason = "EOD_SELL"; + exit_price = c.close; + } else if c.high >= tp_line { + exit_reason = "take_profit"; + exit_price = tp_line; + } else { + let trail_armed = max_price_in_trade >= buy_price * (1.0 + params.shoulder_min_high); + let shoulder_line = if trail_armed { max_price_in_trade * (1.0 - params.shoulder_cut_pct) } else { 0.0 }; + + if trail_armed && c.low <= shoulder_line { + exit_reason = "shoulder_cut"; + exit_price = shoulder_line; + } else if c.low <= sl_line { + exit_reason = "stop_loss"; + exit_price = sl_line; + } else { + let trail_arm_line = buy_price * (1.0 + params.trail_arm_pct); + if max_price_in_trade >= trail_arm_line { + let trail_line = max_price_in_trade * (1.0 - params.trail_pct); + if c.low <= trail_line { + exit_reason = "trailing"; + exit_price = trail_line; + } + } + } + } + + if exit_reason.is_empty() && params.max_hold_bars > 0 && hold_bars >= params.max_hold_bars { + exit_reason = "max_hold"; + exit_price = c.close; + } + + if !exit_reason.is_empty() { + let pnl = (exit_price - buy_price) / buy_price; + trades.push(BreakoutTrade { + code: target_code.to_string(), buy_time: buy_time.clone(), sell_time: c.time_str.clone(), + buy_price, sell_price: exit_price, pnl_pct: pnl * 100.0, reason: exit_reason.to_string(), + resistance: resistance_entry, vol_ratio: vol_ratio_entry, prev_chg: prev_chg_entry, atr_entry, max_price: max_price_in_trade + }); + in_position = false; + last_exit_mins = current_mins; + } + } else { + // ๋งค์ˆ˜ ๋กœ์ง (Breakout) + if hm < params.time_start_hm || hm >= params.time_end_hm { continue; } + if current_mins - last_exit_mins < params.cooldown_min as i64 { continue; } + if daily_cnt >= params.max_daily { continue; } + if c.close < params.min_price { continue; } + + let mut resistance = 0.0; + let mut prev_chg = 0.0; + let mut vol_ratio = 0.0; + + if params.skip_hts_scan_dupes { + // HTS ์Šค์บ” ํ•„ํ„ฐ ์ƒ๋žต + if params.body_min_pct > 0.0 && c.open > 0.0 { + let body_pct = (c.close - c.open) / c.open * 100.0; + if body_pct < params.body_min_pct { continue; } + } + } else { + let prev_c = &candles[i-1]; + let prev_prev_c = &candles[i-2]; + if prev_prev_c.close <= 0.0 { continue; } + prev_chg = (prev_c.close - prev_prev_c.close) / prev_prev_c.close * 100.0; + if prev_chg < params.prev_chg_min || prev_chg > params.prev_chg_max { continue; } + + // ์ €ํ•ญ์„  ๋ŒํŒŒ + let mut max_h = 0.0; + for j in (i - params.lookback_min)..i { + if candles[j].high > max_h { max_h = candles[j].high; } + } + resistance = max_h; + if resistance <= 0.0 || c.close <= resistance { continue; } + + if params.confirm_margin_pct > 0.0 { + let need_price = resistance * (1.0 + params.confirm_margin_pct / 100.0); + if c.close < need_price { continue; } + } + + if params.min_bar_trade_value_krw > 0.0 && c.volume * c.close < params.min_bar_trade_value_krw { + continue; + } + + let use_turnover = params.min_turnover_1m_pct > 0.0; + let use_vol_mult = params.vol_mult > 0.0; + + if use_turnover { + if params.share_denom <= 0.0 { continue; } + let to = c.volume / params.share_denom * 100.0; + if to < params.min_turnover_1m_pct { continue; } + } + + if use_vol_mult { + let mut sum_vol = 0.0; + for j in (i - params.vol_window)..i { sum_vol += candles[j].volume; } + let avg_vol = sum_vol / params.vol_window as f64; + if avg_vol <= 0.0 { continue; } + vol_ratio = c.volume / avg_vol; + if vol_ratio < params.vol_mult { continue; } + } + + if params.body_min_pct > 0.0 && c.open > 0.0 { + let body_pct = (c.close - c.open) / c.open * 100.0; + if body_pct < params.body_min_pct { continue; } + } + if prev_c.close >= c.close { continue; } + + if running_low > 0.0 { + let daily_chg = (running_high - running_low) / running_low * 100.0; + if daily_chg > params.max_daily_chg { continue; } + } + } + + // ์ง„์ž… + in_position = true; + // ์‹ค๋งค๋งค ๋กœ์ง์€ ๋‹ค์Œ๋ด‰ ์‹œ๊ฐ€(next_c.open) ์ง„์ž…์ด ์›์น™์ด์ง€๋งŒ Rust ๊ณ ์† ์—”์ง„์—์„œ๋Š” ๋™์ผ๋ด‰ close ์ง„์ž…(ํ˜น์€ slippage ํฌํ•จ) + // ์—ฌ๊ธฐ์„œ๋Š” ๋‹จ์ˆœ์„ฑ์„ ์œ„ํ•ด current close ์ง„์ž… + buy_price = c.close; + buy_time = c.time_str.clone(); + resistance_entry = resistance; + vol_ratio_entry = vol_ratio; + prev_chg_entry = prev_chg; + max_price_in_trade = buy_price; + hold_bars = 0; + daily_cnt += 1; + atr_entry = atrs[i]; + } + } + + Ok(trades) +} + +#[pyfunction] +pub fn run_engine_trial_breakout(py: Python, session_id: String, params: BreakoutParams) -> PyResult> { + py.allow_threads(move || { + use crate::session_manager::SESSIONS; + use rayon::prelude::*; + let sessions = SESSIONS.read().unwrap(); + let session = sessions.get(&session_id).ok_or_else(|| { + pyo3::exceptions::PyValueError::new_err(format!("Session {} not found", session_id)) + })?; + let all_trades: Vec = session.candles_by_code + .par_iter() + .flat_map(|(code, candles)| { + let mut trades = Vec::new(); + let mut in_position = false; + let mut buy_price = 0.0; + let mut buy_time = String::new(); + let mut resistance_entry = 0.0; + let mut vol_ratio_entry = 0.0; + let mut prev_chg_entry = 0.0; + let mut max_price_in_trade = 0.0; + let mut hold_bars = 0; + let mut atr_entry = 0.0; + + let mut daily_cnt = 0; + let mut cur_day = String::new(); + let mut last_exit_mins = -999; + + let mut running_open = 0.0; + let mut running_high = 0.0; + let mut running_low = 0.0; + + let atrs = compute_atr(candles, params.atr_period); + let need_len = if params.skip_hts_scan_dupes { 1 } else { params.lookback_min.max(params.vol_window) + 2 }; + + for i in need_len..candles.len() { + let c = &candles[i]; + let day = if c.time_str.len() >= 8 { &c.time_str[0..8] } else { "" }; + let hm = parse_hm(&c.time_str); + + if cur_day != day { + cur_day = day.to_string(); + daily_cnt = 0; + last_exit_mins = -999; + running_open = c.open; + running_high = c.high; + running_low = c.low; + } else { + if c.high > running_high { running_high = c.high; } + if c.low < running_low { running_low = c.low; } + } + + let current_mins = parse_mins(&c.time_str); + + if in_position { + hold_bars += 1; + if c.high > max_price_in_trade { max_price_in_trade = c.high; } + + let is_eod = hm >= 1520 && hm <= 1530 && c.time_str.ends_with("1520"); + + let mut exit_reason = ""; + let mut exit_price = 0.0; + + let sl_line = buy_price * (1.0 - params.sl_pct); + let tp_line = buy_price * (1.0 + params.tp_pct); + + if is_eod || hm >= 1530 { + exit_reason = "EOD_SELL"; + exit_price = c.close; + } else if c.high >= tp_line { + exit_reason = "take_profit"; + exit_price = tp_line; + } else { + let trail_armed = max_price_in_trade >= buy_price * (1.0 + params.shoulder_min_high); + let shoulder_line = if trail_armed { max_price_in_trade * (1.0 - params.shoulder_cut_pct) } else { 0.0 }; + + if trail_armed && c.low <= shoulder_line { + exit_reason = "shoulder_cut"; + exit_price = shoulder_line; + } else if c.low <= sl_line { + exit_reason = "stop_loss"; + exit_price = sl_line; + } else { + let trail_arm_line = buy_price * (1.0 + params.trail_arm_pct); + if max_price_in_trade >= trail_arm_line { + let trail_line = max_price_in_trade * (1.0 - params.trail_pct); + if c.low <= trail_line { + exit_reason = "trailing"; + exit_price = trail_line; + } + } + } + } + + if exit_reason.is_empty() && params.max_hold_bars > 0 && hold_bars >= params.max_hold_bars { + exit_reason = "max_hold"; + exit_price = c.close; + } + + if !exit_reason.is_empty() { + let pnl = (exit_price - buy_price) / buy_price; + trades.push(BreakoutTrade { + code: code.clone(), buy_time: buy_time.clone(), sell_time: c.time_str.clone(), + buy_price, sell_price: exit_price, pnl_pct: pnl * 100.0, reason: exit_reason.to_string(), + resistance: resistance_entry, vol_ratio: vol_ratio_entry, prev_chg: prev_chg_entry, atr_entry, max_price: max_price_in_trade + }); + in_position = false; + last_exit_mins = current_mins; + } + } else { + if hm < params.time_start_hm || hm >= params.time_end_hm { continue; } + if current_mins - last_exit_mins < params.cooldown_min as i64 { continue; } + if daily_cnt >= params.max_daily { continue; } + if c.close < params.min_price { continue; } + + let mut resistance = 0.0; + let mut prev_chg = 0.0; + let mut vol_ratio = 0.0; + + if params.skip_hts_scan_dupes { + if params.body_min_pct > 0.0 && c.open > 0.0 { + let body_pct = (c.close - c.open) / c.open * 100.0; + if body_pct < params.body_min_pct { continue; } + } + } else { + let prev_c = &candles[i-1]; + let prev_prev_c = &candles[i-2]; + if prev_prev_c.close <= 0.0 { continue; } + prev_chg = (prev_c.close - prev_prev_c.close) / prev_prev_c.close * 100.0; + if prev_chg < params.prev_chg_min || prev_chg > params.prev_chg_max { continue; } + + let mut max_h = 0.0; + for j in (i - params.lookback_min)..i { + if candles[j].high > max_h { max_h = candles[j].high; } + } + resistance = max_h; + if resistance <= 0.0 || c.close <= resistance { continue; } + + if params.confirm_margin_pct > 0.0 { + let need_price = resistance * (1.0 + params.confirm_margin_pct / 100.0); + if c.close < need_price { continue; } + } + + if params.min_bar_trade_value_krw > 0.0 && c.volume * c.close < params.min_bar_trade_value_krw { + continue; + } + + let use_turnover = params.min_turnover_1m_pct > 0.0; + let use_vol_mult = params.vol_mult > 0.0; + + if use_turnover { + if params.share_denom <= 0.0 { continue; } + let to = c.volume / params.share_denom * 100.0; + if to < params.min_turnover_1m_pct { continue; } + } + + if use_vol_mult { + let mut sum_vol = 0.0; + for j in (i - params.vol_window)..i { sum_vol += candles[j].volume; } + let avg_vol = sum_vol / params.vol_window as f64; + if avg_vol <= 0.0 { continue; } + vol_ratio = c.volume / avg_vol; + if vol_ratio < params.vol_mult { continue; } + } + + if params.body_min_pct > 0.0 && c.open > 0.0 { + let body_pct = (c.close - c.open) / c.open * 100.0; + if body_pct < params.body_min_pct { continue; } + } + if prev_c.close >= c.close { continue; } + + if running_low > 0.0 { + let daily_chg = (running_high - running_low) / running_low * 100.0; + if daily_chg > params.max_daily_chg { continue; } + } + } + + in_position = true; + buy_price = c.close; + buy_time = c.time_str.clone(); + resistance_entry = resistance; + vol_ratio_entry = vol_ratio; + prev_chg_entry = prev_chg; + max_price_in_trade = buy_price; + hold_bars = 0; + daily_cnt += 1; + atr_entry = atrs[i]; + } + } + trades + }) + .collect(); + + Ok(all_trades) + }) +} diff --git a/kis_rust_core/src/db_loader.rs b/kis_rust_src/src/db_loader.rs similarity index 100% rename from kis_rust_core/src/db_loader.rs rename to kis_rust_src/src/db_loader.rs diff --git a/kis_rust_src/src/lib.rs b/kis_rust_src/src/lib.rs new file mode 100644 index 0000000..788b2e3 --- /dev/null +++ b/kis_rust_src/src/lib.rs @@ -0,0 +1,61 @@ +use pyo3::prelude::*; + +pub mod tail; +pub mod db_loader; +pub mod scalp; +pub mod breakout; +pub mod momentum; +pub mod updown_box; +pub mod session_manager; +pub mod parquet_loader; + +use tail::{TailParams, TailTrade, CandleData, run_tail_backtest_fast, run_engine_trial_tail}; +use scalp::{ScalpParams, ScalpTrade, run_scalp_backtest_fast}; +use breakout::{BreakoutParams, BreakoutTrade, run_breakout_backtest_fast}; +use momentum::{MomentumParams, MomentumTrade, run_momentum_backtest_fast}; +use updown_box::{BoxParams, BoxTrade, run_box_backtest_fast}; +use session_manager::{init_backtest_session, clear_backtest_session, TickData, init_backtest_session_json}; + +/// ํŒŒ์ด์ฌ์—์„œ ํ˜ธ์ถœํ•  ๋ฐฑํ…Œ์ŠคํŠธ ๋ฒค์น˜๋งˆํฌ ํ•จ์ˆ˜ +#[pyfunction] +fn run_dummy_backtest(params: &str) -> PyResult { + // ์‹ค์ œ๋กœ๋Š” ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ํŒŒ์‹ฑํ•˜๊ณ  ๋ฃจํ”„๋ฅผ ๋Œ์•„์•ผ ํ•˜์ง€๋งŒ, ์ง€๊ธˆ์€ ์—ฐ๊ฒฐ ํ…Œ์ŠคํŠธ์šฉ + println!("[Rust] ํŒŒ์ด์ฌ์œผ๋กœ๋ถ€ํ„ฐ ๋ฐ›์€ ํŒŒ๋ผ๋ฏธํ„ฐ: {}", params); + let dummy_pnl = 150000.0; // 15๋งŒ์› + Ok(dummy_pnl) +} + +/// ๋ชจ๋“ˆ ์ดˆ๊ธฐํ™” +#[pymodule] +fn kis_rust_core(_py: Python, m: &PyModule) -> PyResult<()> { + m.add_function(wrap_pyfunction!(run_dummy_backtest, m)?)?; + m.add_function(wrap_pyfunction!(run_tail_backtest_fast, m)?)?; + m.add_function(wrap_pyfunction!(run_engine_trial_tail, m)?)?; + m.add_function(wrap_pyfunction!(db_loader::load_candles_from_db, m)?)?; + m.add_function(wrap_pyfunction!(run_scalp_backtest_fast, m)?)?; + m.add_function(wrap_pyfunction!(run_breakout_backtest_fast, m)?)?; + m.add_function(wrap_pyfunction!(breakout::run_engine_trial_breakout, m)?)?; + m.add_function(wrap_pyfunction!(run_momentum_backtest_fast, m)?)?; + m.add_function(wrap_pyfunction!(momentum::run_engine_trial_momentum, m)?)?; + m.add_function(wrap_pyfunction!(run_box_backtest_fast, m)?)?; + m.add_function(wrap_pyfunction!(updown_box::run_engine_trial_box, m)?)?; + m.add_function(wrap_pyfunction!(scalp::run_engine_trial_scalp, m)?)?; + m.add_function(wrap_pyfunction!(init_backtest_session, m)?)?; + m.add_function(wrap_pyfunction!(init_backtest_session_json, m)?)?; + m.add_function(wrap_pyfunction!(clear_backtest_session, m)?)?; + m.add_function(wrap_pyfunction!(parquet_loader::load_parquet_ticks_fast, m)?)?; + + m.add_class::()?; + m.add_class::()?; + m.add_class::()?; + m.add_class::()?; + m.add_class::()?; + m.add_class::()?; + m.add_class::()?; + m.add_class::()?; + m.add_class::()?; + m.add_class::()?; + m.add_class::()?; + m.add_class::()?; + Ok(()) +} diff --git a/kis_rust_src/src/momentum.rs b/kis_rust_src/src/momentum.rs new file mode 100644 index 0000000..bea1427 --- /dev/null +++ b/kis_rust_src/src/momentum.rs @@ -0,0 +1,478 @@ +use pyo3::prelude::*; +use serde::{Deserialize, Serialize}; +use rayon::prelude::*; +use crate::tail::CandleData; + +#[pyclass] +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct MomentumParams { + #[pyo3(get, set)] + pub time_start_hm: usize, + #[pyo3(get, set)] + pub time_end_hm: usize, + #[pyo3(get, set)] + pub cooldown_min: f64, + #[pyo3(get, set)] + pub max_daily: usize, + #[pyo3(get, set)] + pub min_price: f64, + #[pyo3(get, set)] + pub use_defense_filters: bool, + #[pyo3(get, set)] + pub use_high_chase_filter: bool, + #[pyo3(get, set)] + pub high_chase_thr: f64, + #[pyo3(get, set)] + pub trigger_e_confirm: bool, + #[pyo3(get, set)] + pub trigger_require_bull_bar: bool, + #[pyo3(get, set)] + pub use_vol_trigger: bool, + #[pyo3(get, set)] + pub use_rsi_filter: bool, + #[pyo3(get, set)] + pub use_rsi_max_filter: bool, + #[pyo3(get, set)] + pub rsi_period: usize, + #[pyo3(get, set)] + pub mom_rsi_min: f64, + #[pyo3(get, set)] + pub mom_rsi_max: f64, + #[pyo3(get, set)] + pub use_ema_filter: bool, + #[pyo3(get, set)] + pub ema_fast_period: usize, + #[pyo3(get, set)] + pub ema_slow_period: usize, + #[pyo3(get, set)] + pub e_min_chg_pct: f64, + #[pyo3(get, set)] + pub mom_vol_mult: f64, + #[pyo3(get, set)] + pub mom_vol_win: usize, + #[pyo3(get, set)] + pub skip_hts_scan_dupes: bool, + + // ๋งค๋„ ํŒŒ๋ผ๋ฏธํ„ฐ + #[pyo3(get, set)] + pub sl_pct: f64, + #[pyo3(get, set)] + pub tp_pct: f64, + #[pyo3(get, set)] + pub trail_pct: f64, + #[pyo3(get, set)] + pub trail_arm_pct: f64, + #[pyo3(get, set)] + pub shoulder_min_high: f64, + #[pyo3(get, set)] + pub shoulder_cut_pct: f64, + #[pyo3(get, set)] + pub max_hold_bars: usize, + #[pyo3(get, set)] + pub max_loss_krw: f64, + #[pyo3(get, set)] + pub min_hold_sec: f64, + #[pyo3(get, set)] + pub min_drop_pct_for_loss_cut: f64, +} + +#[pymethods] +impl MomentumParams { + #[new] + #[allow(clippy::too_many_arguments)] + pub fn new( + time_start_hm: usize, time_end_hm: usize, cooldown_min: f64, max_daily: usize, + min_price: f64, use_defense_filters: bool, use_high_chase_filter: bool, + high_chase_thr: f64, trigger_e_confirm: bool, trigger_require_bull_bar: bool, + use_vol_trigger: bool, use_rsi_filter: bool, use_rsi_max_filter: bool, rsi_period: usize, mom_rsi_min: f64, + mom_rsi_max: f64, use_ema_filter: bool, ema_fast_period: usize, ema_slow_period: usize, + e_min_chg_pct: f64, mom_vol_mult: f64, mom_vol_win: usize, skip_hts_scan_dupes: bool, + sl_pct: f64, tp_pct: f64, trail_pct: f64, trail_arm_pct: f64, shoulder_min_high: f64, + shoulder_cut_pct: f64, max_hold_bars: usize, max_loss_krw: f64, min_hold_sec: f64, + min_drop_pct_for_loss_cut: f64, + ) -> Self { + Self { + time_start_hm, time_end_hm, cooldown_min, max_daily, min_price, use_defense_filters, + use_high_chase_filter, high_chase_thr, trigger_e_confirm, trigger_require_bull_bar, + use_vol_trigger, use_rsi_filter, use_rsi_max_filter, rsi_period, mom_rsi_min, mom_rsi_max, use_ema_filter, + ema_fast_period, ema_slow_period, e_min_chg_pct, mom_vol_mult, mom_vol_win, + skip_hts_scan_dupes, sl_pct, tp_pct, trail_pct, trail_arm_pct, shoulder_min_high, + shoulder_cut_pct, max_hold_bars, max_loss_krw, min_hold_sec, min_drop_pct_for_loss_cut + } + } +} + +#[pyclass] +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct MomentumTrade { + #[pyo3(get, set)] + pub code: String, + #[pyo3(get, set)] + pub buy_time: String, + #[pyo3(get, set)] + pub sell_time: String, + #[pyo3(get, set)] + pub buy_price: f64, + #[pyo3(get, set)] + pub sell_price: f64, + #[pyo3(get, set)] + pub pnl_pct: f64, + #[pyo3(get, set)] + pub reason: String, + #[pyo3(get, set)] + pub max_price: f64, + #[pyo3(get, set)] + pub rsi_entry: f64, +} + +fn parse_hm(time_str: &str) -> usize { + if time_str.len() >= 12 { time_str[8..12].parse::().unwrap_or(0) } else { 0 } +} + +fn parse_mins(time_str: &str) -> i64 { + if time_str.len() >= 12 { + let h = time_str[8..10].parse::().unwrap_or(0); + let m = time_str[10..12].parse::().unwrap_or(0); + h * 60 + m + } else { 0 } +} + +#[pyfunction] +pub fn run_momentum_backtest_fast( + target_code: &str, + candles: Vec, + params: &MomentumParams, +) -> PyResult> { + let mut trades = Vec::new(); + let mut in_position = false; + let mut buy_price = 0.0; + let mut buy_time = String::new(); + let mut max_price_in_trade = 0.0; + let mut hold_bars = 0; + let mut rsi_entry = 0.0; + + let mut daily_cnt = 0; + let mut cur_day = String::new(); + let mut last_exit_mins = -999; + + // ๋‹จ์ˆœํ™”: ๊ณ ์  ์ถ”๊ฒฉ ํ•„ํ„ฐ์šฉ + let mut running_high = 0.0; + + let need_len = 6; + + for i in need_len..candles.len() { + let c = &candles[i]; + let day = if c.time_str.len() >= 8 { &c.time_str[0..8] } else { "" }; + let hm = parse_hm(&c.time_str); + + if cur_day != day { + cur_day = day.to_string(); + daily_cnt = 0; + last_exit_mins = -999; + running_high = c.high; + } else { + if c.high > running_high { running_high = c.high; } + } + + let current_mins = parse_mins(&c.time_str); + + if in_position { + hold_bars += 1; + if c.high > max_price_in_trade { max_price_in_trade = c.high; } + + let is_eod = hm >= 1520 && hm <= 1530 && c.time_str.ends_with("1520"); + + let mut exit_reason = ""; + let mut exit_price = 0.0; + + let sl_line = buy_price * (1.0 - params.sl_pct); + let tp_line = buy_price * (1.0 + params.tp_pct); + + if is_eod || hm >= 1530 { + exit_reason = "์žฅ๋งˆ๊ฐ์ฒญ์‚ฐ"; + exit_price = c.close; + } else if c.high >= tp_line { + exit_reason = "์ต์ ˆ"; + exit_price = tp_line; + } else { + let shoulder_armed = max_price_in_trade >= buy_price * (1.0 + params.shoulder_min_high); + let shoulder_line = if shoulder_armed && params.shoulder_cut_pct > 0.0 { + max_price_in_trade * (1.0 - params.shoulder_cut_pct) + } else { 0.0 }; + + if shoulder_armed && c.low <= shoulder_line { + exit_reason = "์–ด๊นจ์ปท"; + exit_price = shoulder_line; + } else if c.low <= sl_line { + exit_reason = "์†์ ˆ"; + exit_price = sl_line; + } else { + if params.trail_pct > 0.0 && max_price_in_trade > buy_price { + let trail_arm_line = buy_price * (1.0 + params.trail_arm_pct); + if params.trail_arm_pct <= 0.0 || max_price_in_trade >= trail_arm_line { + let trail_line = max_price_in_trade * (1.0 - params.trail_pct); + if c.low <= trail_line { + exit_reason = "ํŠธ๋ ˆ์ผ์ปท"; + exit_price = trail_line; + } + } + } + } + } + + if exit_reason.is_empty() && params.max_hold_bars > 0 && hold_bars >= params.max_hold_bars { + exit_reason = "์‹œ๊ฐ„์ปท"; + exit_price = c.close; + } + + // ๊ธˆ์•ก์†์‹ค์ปท (๋‹จ์ˆœํ™”) + let drop_pct = if buy_price > 0.0 { (buy_price - c.low) / buy_price } else { 0.0 }; + if exit_reason.is_empty() && drop_pct >= params.min_drop_pct_for_loss_cut { + exit_reason = "๊ธˆ์•ก์†์‹ค์ปท"; + exit_price = c.low; + } + + if !exit_reason.is_empty() { + let pnl = (exit_price - buy_price) / buy_price; + trades.push(MomentumTrade { + code: target_code.to_string(), buy_time: buy_time.clone(), sell_time: c.time_str.clone(), + buy_price, sell_price: exit_price, pnl_pct: pnl * 100.0, reason: exit_reason.to_string(), + max_price: max_price_in_trade, rsi_entry + }); + in_position = false; + last_exit_mins = current_mins; + } + } else { + // ๋งค์ˆ˜ ํŒ๋‹จ (Momentum) + if hm < params.time_start_hm || hm >= params.time_end_hm { continue; } + if current_mins - last_exit_mins < params.cooldown_min as i64 { continue; } + if daily_cnt >= params.max_daily { continue; } + + if params.use_defense_filters && c.close < params.min_price { continue; } + + if params.skip_hts_scan_dupes { + if params.use_rsi_filter { + if c.rsi < params.mom_rsi_min || (params.use_rsi_max_filter && c.rsi > params.mom_rsi_max) { continue; } + } + // HTS ์Šค์บ” ์ƒ๋žต์ด๋ฉด ์ง„์ž… + } else { + let prev_c = &candles[i-1]; + let mut prev_day_close = 0.0; + for j in (0..i).rev() { + let d = if candles[j].time_str.len() >= 8 { &candles[j].time_str[0..8] } else { "" }; + if d < day { + prev_day_close = candles[j].close; + break; + } + } + + if params.trigger_e_confirm { + if prev_day_close <= 0.0 { continue; } + let threshold = prev_day_close * (1.0 + params.e_min_chg_pct / 100.0); + if c.close < threshold { continue; } + } + + if params.trigger_require_bull_bar && c.open > 0.0 && c.close <= c.open { continue; } + + if params.use_vol_trigger && params.mom_vol_mult > 0.0 { + let win = params.mom_vol_win.max(1); + let mut sum_vol = 0.0; + for j in (i - win)..i { sum_vol += candles[j].volume; } + let avg = sum_vol / win as f64; + if avg <= 0.0 || c.volume < avg * params.mom_vol_mult { continue; } + } + + if params.use_high_chase_filter && running_high > 0.0 && c.close >= running_high * params.high_chase_thr { + continue; + } + + if params.use_rsi_filter { + if c.rsi < params.mom_rsi_min { continue; } + if c.rsi > params.mom_rsi_max { continue; } + } + } + + in_position = true; + buy_price = c.close; + buy_time = c.time_str.clone(); + max_price_in_trade = buy_price; + hold_bars = 0; + daily_cnt += 1; + rsi_entry = c.rsi; + } + } + + Ok(trades) +} + +#[pyfunction] +pub fn run_engine_trial_momentum(py: Python, session_id: String, params: MomentumParams) -> PyResult> { + py.allow_threads(move || { + use crate::session_manager::SESSIONS; + use rayon::prelude::*; + let sessions = SESSIONS.read().unwrap(); + let session = sessions.get(&session_id).ok_or_else(|| { + pyo3::exceptions::PyValueError::new_err(format!("Session {} not found", session_id)) + })?; + let all_trades: Vec = session.candles_by_code + .par_iter() + .flat_map(|(code, candles)| { + let mut trades = Vec::new(); + let mut in_position = false; + let mut buy_price = 0.0; + let mut buy_time = String::new(); + let mut max_price_in_trade = 0.0; + let mut hold_bars = 0; + let mut rsi_entry = 0.0; + + let mut daily_cnt = 0; + let mut cur_day = String::new(); + let mut last_exit_mins = -999; + + let mut running_high = 0.0; + let need_len = 6; + + for i in need_len..candles.len() { + let c = &candles[i]; + let day = if c.time_str.len() >= 8 { &c.time_str[0..8] } else { "" }; + let hm = parse_hm(&c.time_str); + + if cur_day != day { + cur_day = day.to_string(); + daily_cnt = 0; + last_exit_mins = -999; + running_high = c.high; + } else { + if c.high > running_high { running_high = c.high; } + } + + let current_mins = parse_mins(&c.time_str); + + if in_position { + hold_bars += 1; + if c.high > max_price_in_trade { max_price_in_trade = c.high; } + + let is_eod = hm >= 1520 && hm <= 1530 && c.time_str.ends_with("1520"); + + let mut exit_reason = ""; + let mut exit_price = 0.0; + + let sl_line = buy_price * (1.0 - params.sl_pct); + let tp_line = buy_price * (1.0 + params.tp_pct); + + if is_eod || hm >= 1530 { + exit_reason = "์žฅ๋งˆ๊ฐ์ฒญ์‚ฐ"; + exit_price = c.close; + } else if c.high >= tp_line { + exit_reason = "์ต์ ˆ"; + exit_price = tp_line; + } else { + let shoulder_armed = max_price_in_trade >= buy_price * (1.0 + params.shoulder_min_high); + let shoulder_line = if shoulder_armed && params.shoulder_cut_pct > 0.0 { + max_price_in_trade * (1.0 - params.shoulder_cut_pct) + } else { 0.0 }; + + if shoulder_armed && c.low <= shoulder_line { + exit_reason = "์–ด๊นจ์ปท"; + exit_price = shoulder_line; + } else if c.low <= sl_line { + exit_reason = "์†์ ˆ"; + exit_price = sl_line; + } else { + if params.trail_pct > 0.0 && max_price_in_trade > buy_price { + let trail_arm_line = buy_price * (1.0 + params.trail_arm_pct); + if params.trail_arm_pct <= 0.0 || max_price_in_trade >= trail_arm_line { + let trail_line = max_price_in_trade * (1.0 - params.trail_pct); + if c.low <= trail_line { + exit_reason = "ํŠธ๋ ˆ์ผ์ปท"; + exit_price = trail_line; + } + } + } + } + } + + if exit_reason.is_empty() && params.max_hold_bars > 0 && hold_bars >= params.max_hold_bars { + exit_reason = "์‹œ๊ฐ„์ปท"; + exit_price = c.close; + } + + let drop_pct = if buy_price > 0.0 { (buy_price - c.low) / buy_price } else { 0.0 }; + if exit_reason.is_empty() && drop_pct >= params.min_drop_pct_for_loss_cut { + exit_reason = "๊ธˆ์•ก์†์‹ค์ปท"; + exit_price = c.low; + } + + if !exit_reason.is_empty() { + let pnl = (exit_price - buy_price) / buy_price; + trades.push(MomentumTrade { + code: code.clone(), buy_time: buy_time.clone(), sell_time: c.time_str.clone(), + buy_price, sell_price: exit_price, pnl_pct: pnl * 100.0, reason: exit_reason.to_string(), + max_price: max_price_in_trade, rsi_entry + }); + in_position = false; + last_exit_mins = current_mins; + } + } else { + if hm < params.time_start_hm || hm >= params.time_end_hm { continue; } + if current_mins - last_exit_mins < params.cooldown_min as i64 { continue; } + if daily_cnt >= params.max_daily { continue; } + + if params.use_defense_filters && c.close < params.min_price { continue; } + + if params.skip_hts_scan_dupes { + if params.use_rsi_filter { + if c.rsi < params.mom_rsi_min || (params.use_rsi_max_filter && c.rsi > params.mom_rsi_max) { continue; } + } + } else { + let mut prev_day_close = 0.0; + for j in (0..i).rev() { + let d = if candles[j].time_str.len() >= 8 { &candles[j].time_str[0..8] } else { "" }; + if d < day { + prev_day_close = candles[j].close; + break; + } + } + + if params.trigger_e_confirm { + if prev_day_close <= 0.0 { continue; } + let threshold = prev_day_close * (1.0 + params.e_min_chg_pct / 100.0); + if c.close < threshold { continue; } + } + + if params.trigger_require_bull_bar && c.open > 0.0 && c.close <= c.open { continue; } + + if params.use_vol_trigger && params.mom_vol_mult > 0.0 { + let win = params.mom_vol_win.max(1); + let mut sum_vol = 0.0; + for j in (i - win)..i { sum_vol += candles[j].volume; } + let avg = sum_vol / win as f64; + if avg <= 0.0 || c.volume < avg * params.mom_vol_mult { continue; } + } + + if params.use_high_chase_filter && running_high > 0.0 && c.close >= running_high * params.high_chase_thr { + continue; + } + + if params.use_rsi_filter { + if c.rsi < params.mom_rsi_min { continue; } + if c.rsi > params.mom_rsi_max { continue; } + } + } + + in_position = true; + buy_price = c.close; + buy_time = c.time_str.clone(); + max_price_in_trade = buy_price; + hold_bars = 0; + daily_cnt += 1; + rsi_entry = c.rsi; + } + } + trades + }) + .collect(); + + Ok(all_trades) + }) +} diff --git a/kis_rust_src/src/parquet_loader.rs b/kis_rust_src/src/parquet_loader.rs new file mode 100644 index 0000000..2719bdb --- /dev/null +++ b/kis_rust_src/src/parquet_loader.rs @@ -0,0 +1,119 @@ +use pyo3::prelude::*; +use pyo3::types::{PyDict, PyList}; +use polars::prelude::*; +use chrono::NaiveDateTime; +use std::collections::HashSet; + +#[pyfunction] +pub fn load_parquet_ticks_fast( + py: Python, + path: &str, + start_time: &str, + end_time: &str, + codes: Option>, + tick_source: Option +) -> PyResult { + + // 1. Load Parquet + let df = LazyFrame::scan_parquet(path.into(), Default::default()) + .map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(format!("Parquet scan error: {}", e)))? + .collect() + .map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(format!("Parquet collect error: {}", e)))?; + + // 2. Extract Columns + let code_s = df.column("code").map_err(|e| pyo3::exceptions::PyValueError::new_err(e.to_string()))?.str().map_err(|e| pyo3::exceptions::PyValueError::new_err(e.to_string()))?; + let tt_s = df.column("tick_time").map_err(|e| pyo3::exceptions::PyValueError::new_err(e.to_string()))?.str().map_err(|e| pyo3::exceptions::PyValueError::new_err(e.to_string()))?; + let price_s = df.column("price").map_err(|e| pyo3::exceptions::PyValueError::new_err(e.to_string()))?.f64().map_err(|e| pyo3::exceptions::PyValueError::new_err(e.to_string()))?; + let volume_s = df.column("volume").map_err(|e| pyo3::exceptions::PyValueError::new_err(e.to_string()))?.i64().map_err(|e| pyo3::exceptions::PyValueError::new_err(e.to_string()))?; + let source_s = df.column("source").map_err(|e| pyo3::exceptions::PyValueError::new_err(e.to_string()))?.str().map_err(|e| pyo3::exceptions::PyValueError::new_err(e.to_string()))?; + + let recv_s = df.column("recv_ts").ok().and_then(|c| c.str().ok()); + let raw_s = df.column("tick_time_raw").ok().and_then(|c| c.str().ok()); + + let out_dict = PyDict::new(py); + let mut total_rows = 0; + + let codes_set: Option> = codes.map(|c| c.into_iter().collect()); + + for i in 0..df.height() { + let code = code_s.get(i).unwrap_or(""); + let tt = tt_s.get(i).unwrap_or(""); + let price = price_s.get(i).unwrap_or(0.0); + let volume = volume_s.get(i).unwrap_or(0); + let source = source_s.get(i).unwrap_or(""); + + // Apply filters manually + if tt < start_time || tt > end_time { + continue; + } + + if let Some(ref cs) = codes_set { + if !cs.contains(code) { + continue; + } + } + + if let Some(ref s) = tick_source { + if !s.is_empty() && source != s { + continue; + } + } + + if tt.len() < 12 { continue; } + let minute_key = &tt[0..12]; + + let mut lag_sec: Option = None; + if let Some(rs) = recv_s { + if let Some(recv_ts_str) = rs.get(i) { + if recv_ts_str.len() >= 19 { + let pkt_raw = raw_s.and_then(|r| r.get(i)).unwrap_or(tt); + if let (Ok(r_dt), Ok(p_dt)) = ( + NaiveDateTime::parse_from_str(&recv_ts_str[0..19], "%Y-%m-%d %H:%M:%S"), + NaiveDateTime::parse_from_str(if pkt_raw.len() >= 14 { &pkt_raw[0..14] } else { tt }, "%Y%m%d%H%M%S") + ) { + lag_sec = Some((r_dt.timestamp() - p_dt.timestamp()) as i32); + } + } + } + } + + let tick_dict = PyDict::new(py); + tick_dict.set_item("code", code)?; + tick_dict.set_item("tick_time", tt)?; + tick_dict.set_item("price", price)?; + tick_dict.set_item("volume", volume)?; + tick_dict.set_item("source", source)?; + if let Some(l) = lag_sec { + tick_dict.set_item("_lag_sec", l)?; + } else { + tick_dict.set_item("_lag_sec", py.None())?; + } + + let code_dict = match out_dict.get_item(code)? { + Some(d) => d.downcast::()?, + None => { + let d = PyDict::new(py); + out_dict.set_item(code, d)?; + d + } + }; + + let min_list = match code_dict.get_item(minute_key)? { + Some(l) => l.downcast::()?, + None => { + let l = PyList::empty(py); + code_dict.set_item(minute_key, l)?; + l + } + }; + + min_list.append(tick_dict)?; + total_rows += 1; + } + + let result = PyDict::new(py); + result.set_item("data", out_dict)?; + result.set_item("count", total_rows)?; + + Ok(result.into()) +} diff --git a/kis_rust_core/src/scalp.rs b/kis_rust_src/src/scalp.rs similarity index 58% rename from kis_rust_core/src/scalp.rs rename to kis_rust_src/src/scalp.rs index fc4a5a8..5299815 100644 --- a/kis_rust_core/src/scalp.rs +++ b/kis_rust_src/src/scalp.rs @@ -1,5 +1,6 @@ use pyo3::prelude::*; use serde::{Deserialize, Serialize}; +use rayon::prelude::*; use crate::tail::CandleData; #[pyclass] @@ -311,3 +312,147 @@ pub fn run_scalp_backtest_fast( Ok(trades) } + +#[pyfunction] +pub fn run_engine_trial_scalp(py: Python, session_id: String, params: ScalpParams) -> PyResult> { + py.allow_threads(move || { + use crate::session_manager::SESSIONS; + use rayon::prelude::*; + let sessions = SESSIONS.read().unwrap(); + let session = sessions.get(&session_id).ok_or_else(|| { + pyo3::exceptions::PyValueError::new_err(format!("Session {} not found", session_id)) + })?; + + let all_trades: Vec = session.candles_by_code + .par_iter() + .flat_map(|(code, candles)| { + let mut trades = Vec::new(); + let mut in_position = false; + let mut buy_price = 0.0; + let mut buy_time = String::new(); + let mut rsi_entry = 0.0; + + let mut daily_cnt = 0; + let mut cur_day = String::new(); + let mut last_exit_mins = -999; + + let closes: Vec = candles.iter().map(|c| c.close).collect(); + let rsis = compute_rsi_series(&closes, params.rsi_period); + + let mut running_open = 0.0; + let mut running_high = 0.0; + let mut running_low = 0.0; + + for i in params.rsi_period..candles.len() { + let c = &candles[i]; + let day = if c.time_str.len() >= 8 { &c.time_str[0..8] } else { "" }; + let hm = parse_hm(&c.time_str); + + if cur_day != day { + cur_day = day.to_string(); + daily_cnt = 0; + last_exit_mins = -999; + running_open = c.open; + running_high = c.high; + running_low = c.low; + } else { + if c.high > running_high { running_high = c.high; } + if c.low < running_low { running_low = c.low; } + } + + let current_mins = parse_mins(&c.time_str); + + if in_position { + let pnl = (c.close - buy_price) / buy_price; + + let is_eod = hm >= 1520 && hm <= 1530 && c.time_str.ends_with("1520"); + if is_eod || hm >= 1530 { + trades.push(ScalpTrade { + code: code.clone(), buy_time: buy_time.clone(), sell_time: c.time_str.clone(), + buy_price, sell_price: c.close, pnl_pct: pnl * 100.0, reason: "EOD_SELL".to_string(), rsi_entry + }); + in_position = false; + last_exit_mins = current_mins; + } + else if pnl >= params.tp_pct { + trades.push(ScalpTrade { + code: code.clone(), buy_time: buy_time.clone(), sell_time: c.time_str.clone(), + buy_price, sell_price: c.close, pnl_pct: pnl * 100.0, reason: "TP_REACHED".to_string(), rsi_entry + }); + in_position = false; + last_exit_mins = current_mins; + } + else if pnl <= -params.sl_pct { + trades.push(ScalpTrade { + code: code.clone(), buy_time: buy_time.clone(), sell_time: c.time_str.clone(), + buy_price, sell_price: c.close, pnl_pct: pnl * 100.0, reason: "SL_REACHED".to_string(), rsi_entry + }); + in_position = false; + last_exit_mins = current_mins; + } + } else { + if hm < params.time_start_hm || hm >= params.time_end_hm { continue; } + if current_mins - last_exit_mins < params.cooldown_min as i64 { continue; } + if daily_cnt >= params.max_daily { continue; } + + if params.use_defense_filters { + if c.close < params.min_price { continue; } + if running_open > 0.0 && !params.skip_hts { + let dr = (running_open - running_low) / running_open; + if dr < params.drop_rate { continue; } + if c.close >= running_high * params.high_chase_thr { continue; } + let daily_chg_pct = (running_high - running_low) / running_low * 100.0; + if daily_chg_pct > params.max_daily_chg { continue; } + } + } + + if !params.skip_hts && params.vol_mult > 0.0 { + let win = if i > 20 { 20 } else { i }; + if win > 0 { + let mut sum_vol = 0.0; + for j in (i - win)..i { + sum_vol += candles[j].volume; + } + let avg_vol = sum_vol / win as f64; + if avg_vol > 0.0 && c.volume < avg_vol * params.vol_mult { continue; } + } + } + + let rsi = rsis[i]; + + if params.skip_hts { + in_position = true; + buy_price = c.close; + buy_time = c.time_str.clone(); + rsi_entry = rsi; + daily_cnt += 1; + } else { + if i < 2 { continue; } + let prev_rsi = rsis[i-1]; + let prev2_rsi = rsis[i-2]; + + if rsi <= 0.0 || rsi > params.rsi_overbought { continue; } + + let is_v_rebound = (prev2_rsi <= params.rsi_oversold || prev_rsi <= params.rsi_oversold) && rsi > prev_rsi; + + let prev_c = &candles[i-1]; + let prev_bear = prev_c.close < prev_c.open; + let curr_bull = c.close > c.open; + + if is_v_rebound && (prev_bear && curr_bull) { + in_position = true; + buy_price = c.close; + buy_time = c.time_str.clone(); + rsi_entry = rsi; + daily_cnt += 1; + } + } + } + } + trades + }) + .collect(); + + Ok(all_trades) + }) +} diff --git a/kis_rust_src/src/session_manager.rs b/kis_rust_src/src/session_manager.rs new file mode 100644 index 0000000..7230d8a --- /dev/null +++ b/kis_rust_src/src/session_manager.rs @@ -0,0 +1,79 @@ +use pyo3::prelude::*; +use std::collections::HashMap; +use std::sync::RwLock; +use lazy_static::lazy_static; +use crate::tail::CandleData; +use serde::{Deserialize, Serialize}; + +// TickData ๊ตฌ์กฐ์ฒด ์ •์˜ (์ž„์‹œ, ํ•„์š”์‹œ ํ™•์žฅ) +#[pyclass] +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct TickData { + #[pyo3(get, set)] + pub time_str: String, + #[pyo3(get, set)] + pub price: f64, +} + +#[pymethods] +impl TickData { + #[new] + pub fn new(time_str: String, price: f64) -> Self { + Self { time_str, price } + } +} + +pub struct BacktestSessionData { + pub candles_by_code: HashMap>, + pub ticks_by_code: HashMap>, +} + +lazy_static! { + pub static ref SESSIONS: RwLock> = RwLock::new(HashMap::new()); +} + +#[pyfunction] +pub fn init_backtest_session( + session_id: String, + candles_by_code: HashMap>, + ticks_by_code: HashMap>, +) -> PyResult<()> { + let mut sessions = SESSIONS.write().unwrap(); + sessions.insert( + session_id.clone(), + BacktestSessionData { + candles_by_code, + ticks_by_code, + }, + ); + println!("[Rust] Session {} initialized.", session_id); + Ok(()) +} + +#[pyfunction] +pub fn clear_backtest_session(session_id: String) -> PyResult<()> { + let mut sessions = SESSIONS.write().unwrap(); + sessions.remove(&session_id); + println!("[Rust] Session {} cleared.", session_id); + Ok(()) +} + +#[pyfunction] +pub fn init_backtest_session_json( + session_id: String, + candles_json: String, +) -> PyResult<()> { + let candles_by_code: HashMap> = serde_json::from_str(&candles_json) + .map_err(|e| pyo3::exceptions::PyValueError::new_err(format!("JSON parsing error: {}", e)))?; + + let mut sessions = SESSIONS.write().unwrap(); + sessions.insert( + session_id.clone(), + BacktestSessionData { + candles_by_code, + ticks_by_code: HashMap::new(), + }, + ); + println!("[Rust] Session {} initialized via JSON. ({} codes)", session_id, sessions.get(&session_id).unwrap().candles_by_code.len()); + Ok(()) +} diff --git a/kis_rust_src/src/tail.rs b/kis_rust_src/src/tail.rs new file mode 100644 index 0000000..17b4c99 --- /dev/null +++ b/kis_rust_src/src/tail.rs @@ -0,0 +1,452 @@ +use pyo3::prelude::*; +use serde::{Deserialize, Serialize}; +use rayon::prelude::*; + +#[pyclass] +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct TailParams { + #[pyo3(get, set)] + pub time_start_hm: usize, + #[pyo3(get, set)] + pub time_end_hm: usize, + #[pyo3(get, set)] + pub cooldown_min: f64, + #[pyo3(get, set)] + pub max_daily: usize, + #[pyo3(get, set)] + pub min_price: f64, + + // Tail ์ง„์ž… ์กฐ๊ฑด + #[pyo3(get, set)] + pub rsi_limit: f64, + #[pyo3(get, set)] + pub drop_pct_min: f64, + #[pyo3(get, set)] + pub tail_recovery_min: f64, + #[pyo3(get, set)] + pub tail_pct_min: f64, + #[pyo3(get, set)] + pub tail_ratio_min: f64, + #[pyo3(get, set)] + pub pattern_hammer: bool, + #[pyo3(get, set)] + pub pattern_pin: bool, + #[pyo3(get, set)] + pub pattern_engulfing: bool, + #[pyo3(get, set)] + pub pattern_piercing: bool, + #[pyo3(get, set)] + pub pattern_harami: bool, + #[pyo3(get, set)] + pub pattern_doji: bool, + #[pyo3(get, set)] + pub pattern_morning_star: bool, + #[pyo3(get, set)] + pub skip_hts_scan_dupes: bool, + + // ๋งค๋„ ํŒŒ๋ผ๋ฏธํ„ฐ + #[pyo3(get, set)] + pub sl_pct: f64, + #[pyo3(get, set)] + pub tp_pct: f64, + #[pyo3(get, set)] + pub trail_pct: f64, + #[pyo3(get, set)] + pub trail_arm_pct: f64, + #[pyo3(get, set)] + pub shoulder_min_high: f64, + #[pyo3(get, set)] + pub shoulder_cut_pct: f64, + #[pyo3(get, set)] + pub max_hold_bars: usize, + #[pyo3(get, set)] + pub max_loss_krw: f64, + #[pyo3(get, set)] + pub min_drop_pct_for_loss_cut: f64, +} + +#[pymethods] +impl TailParams { + #[new] + #[allow(clippy::too_many_arguments)] + pub fn new( + time_start_hm: usize, time_end_hm: usize, cooldown_min: f64, max_daily: usize, min_price: f64, + rsi_limit: f64, drop_pct_min: f64, tail_recovery_min: f64, tail_pct_min: f64, tail_ratio_min: f64, + pattern_hammer: bool, pattern_pin: bool, pattern_engulfing: bool, pattern_piercing: bool, + pattern_harami: bool, pattern_doji: bool, pattern_morning_star: bool, skip_hts_scan_dupes: bool, + sl_pct: f64, tp_pct: f64, trail_pct: f64, trail_arm_pct: f64, shoulder_min_high: f64, + shoulder_cut_pct: f64, max_hold_bars: usize, max_loss_krw: f64, min_drop_pct_for_loss_cut: f64, + ) -> Self { + TailParams { + time_start_hm, time_end_hm, cooldown_min, max_daily, min_price, + rsi_limit, drop_pct_min, tail_recovery_min, tail_pct_min, tail_ratio_min, + pattern_hammer, pattern_pin, pattern_engulfing, pattern_piercing, + pattern_harami, pattern_doji, pattern_morning_star, skip_hts_scan_dupes, + sl_pct, tp_pct, trail_pct, trail_arm_pct, shoulder_min_high, + shoulder_cut_pct, max_hold_bars, max_loss_krw, min_drop_pct_for_loss_cut, + } + } +} + +/// ๊ผฌ๋ฆฌ์žก๊ธฐ์šฉ ์บ”๋“ค ์ •๋ณด +#[pyclass] +#[derive(Debug, Clone, Serialize, Deserialize, Default)] +#[serde(default)] +pub struct CandleData { + #[pyo3(get, set)] + #[serde(alias = "candle_time")] + pub time_str: String, + #[pyo3(get, set)] + pub open: f64, + #[pyo3(get, set)] + pub high: f64, + #[pyo3(get, set)] + pub low: f64, + #[pyo3(get, set)] + pub close: f64, + #[pyo3(get, set)] + pub volume: f64, + #[pyo3(get, set)] + #[serde(alias = "RSI")] + pub rsi: f64, +} + +#[pymethods] +impl CandleData { + #[new] + pub fn new(time_str: String, open: f64, high: f64, low: f64, close: f64, volume: f64, rsi: f64) -> Self { + Self { time_str, open, high, low, close, volume, rsi } + } +} + +#[pyclass] +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct TailTrade { + #[pyo3(get, set)] + pub code: String, + #[pyo3(get, set)] + pub buy_time: String, + #[pyo3(get, set)] + pub sell_time: String, + #[pyo3(get, set)] + pub buy_price: f64, + #[pyo3(get, set)] + pub sell_price: f64, + #[pyo3(get, set)] + pub pnl_pct: f64, + #[pyo3(get, set)] + pub reason: String, + #[pyo3(get, set)] + pub max_price: f64, + #[pyo3(get, set)] + pub rsi_entry: f64, +} + +fn parse_hm(time_str: &str) -> usize { + if time_str.len() >= 12 { time_str[8..12].parse::().unwrap_or(0) } else { 0 } +} + +fn parse_mins(time_str: &str) -> i64 { + if time_str.len() >= 12 { + let h = time_str[8..10].parse::().unwrap_or(0); + let m = time_str[10..12].parse::().unwrap_or(0); + h * 60 + m + } else { 0 } +} + +/// ๋‹จ์ผ ์ข…๋ชฉ ๋ฐฑํ…Œ์ŠคํŠธ ์‹œ๋ฎฌ๋ ˆ์ดํ„ฐ (๊ผฌ๋ฆฌ์žก๊ธฐ) +#[pyfunction] +pub fn run_tail_backtest_fast(target_code: &str, candles: Vec, params: &TailParams) -> PyResult> { + let mut trades = Vec::new(); + let mut in_position = false; + let mut buy_price = 0.0; + let mut buy_time = String::new(); + let mut max_price_in_trade = 0.0; + let mut hold_bars = 0; + let mut rsi_entry = 0.0; + + let mut daily_cnt = 0; + let mut cur_day = String::new(); + let mut last_exit_mins = -999; + + for c in &candles { + let day = if c.time_str.len() >= 8 { &c.time_str[0..8] } else { "" }; + let hm = parse_hm(&c.time_str); + + if cur_day != day { + cur_day = day.to_string(); + daily_cnt = 0; + last_exit_mins = -999; + } + + let current_mins = parse_mins(&c.time_str); + + if in_position { + hold_bars += 1; + if c.high > max_price_in_trade { max_price_in_trade = c.high; } + + let is_eod = hm >= 1520 && hm <= 1530 && c.time_str.ends_with("1520"); + + let mut exit_reason = ""; + let mut exit_price = 0.0; + + let sl_line = buy_price * (1.0 - params.sl_pct); + let tp_line = buy_price * (1.0 + params.tp_pct); + + if is_eod || hm >= 1530 { + exit_reason = "์žฅ๋งˆ๊ฐ์ฒญ์‚ฐ"; + exit_price = c.close; + } else if c.high >= tp_line { + exit_reason = "์ต์ ˆ"; + exit_price = tp_line; + } else { + let shoulder_armed = max_price_in_trade >= buy_price * (1.0 + params.shoulder_min_high); + let shoulder_line = if shoulder_armed && params.shoulder_cut_pct > 0.0 { + max_price_in_trade * (1.0 - params.shoulder_cut_pct) + } else { 0.0 }; + + if shoulder_armed && c.low <= shoulder_line { + exit_reason = "์–ด๊นจ์ปท"; + exit_price = shoulder_line; + } else if c.low <= sl_line { + exit_reason = "์†์ ˆ"; + exit_price = sl_line; + } else { + if params.trail_pct > 0.0 && max_price_in_trade > buy_price { + let trail_arm_line = buy_price * (1.0 + params.trail_arm_pct); + if params.trail_arm_pct <= 0.0 || max_price_in_trade >= trail_arm_line { + let trail_line = max_price_in_trade * (1.0 - params.trail_pct); + if c.low <= trail_line { + exit_reason = "ํŠธ๋ ˆ์ผ์ปท"; + exit_price = trail_line; + } + } + } + } + } + + if exit_reason.is_empty() && params.max_hold_bars > 0 && hold_bars >= params.max_hold_bars { + exit_reason = "์‹œ๊ฐ„์ปท"; + exit_price = c.close; + } + + let drop_pct = if buy_price > 0.0 { (buy_price - c.low) / buy_price } else { 0.0 }; + if exit_reason.is_empty() && drop_pct >= params.min_drop_pct_for_loss_cut { + exit_reason = "๊ธˆ์•ก์†์‹ค์ปท"; + exit_price = c.low; + } + + if !exit_reason.is_empty() { + let pnl = (exit_price - buy_price) / buy_price; + trades.push(TailTrade { + code: target_code.to_string(), buy_time: buy_time.clone(), sell_time: c.time_str.clone(), + buy_price, sell_price: exit_price, pnl_pct: pnl * 100.0, reason: exit_reason.to_string(), + max_price: max_price_in_trade, rsi_entry + }); + in_position = false; + last_exit_mins = current_mins; + } + } else { + // ๋งค์ˆ˜ ํŒ๋‹จ + if hm < params.time_start_hm || hm >= params.time_end_hm { continue; } + if current_mins - last_exit_mins < params.cooldown_min as i64 { continue; } + if daily_cnt >= params.max_daily { continue; } + if c.close < params.min_price { continue; } + + if !params.skip_hts_scan_dupes { + if c.rsi > params.rsi_limit { continue; } + let high_low = c.high - c.low; + if high_low <= 0.0 { continue; } + + let drop_pct = (c.open - c.low) / c.open; + if drop_pct < params.drop_pct_min { continue; } + + let recovery = (c.close - c.low) / high_low; + if recovery < params.tail_recovery_min { continue; } + + let tail_len = c.close.min(c.open) - c.low; + let tail_pct = tail_len / c.close; + if tail_pct < params.tail_pct_min { continue; } + } + + in_position = true; + buy_price = c.close; + buy_time = c.time_str.clone(); + max_price_in_trade = buy_price; + hold_bars = 0; + daily_cnt += 1; + rsi_entry = c.rsi; + } + } + + Ok(trades) +} + +#[pyfunction] +pub fn run_engine_trial_tail(py: Python, session_id: String, params: TailParams) -> PyResult> { + py.allow_threads(move || { + use crate::session_manager::SESSIONS; + use rayon::prelude::*; + let sessions = SESSIONS.read().unwrap(); + let session = sessions.get(&session_id).ok_or_else(|| { + pyo3::exceptions::PyValueError::new_err(format!("Session {} not found", session_id)) + })?; + let all_trades: Vec = session.candles_by_code + .par_iter() + .flat_map(|(code, candles)| { + let mut trades = Vec::new(); + let mut in_position = false; + let mut buy_price = 0.0; + let mut buy_time = String::new(); + let mut max_price_in_trade = 0.0; + let mut hold_bars = 0; + let mut rsi_entry = 0.0; + + let mut daily_cnt = 0; + let mut cur_day = String::new(); + let mut last_exit_mins: i64 = -999; + + for i in 0..candles.len() { + let c = &candles[i]; + if c.time_str.len() < 12 { continue; } + let day = &c.time_str[0..8]; + let hm = parse_hm(&c.time_str); + + if cur_day != day { + cur_day = day.to_string(); + daily_cnt = 0; + last_exit_mins = -999; + } + + let current_mins = parse_mins(&c.time_str); + + if in_position { + hold_bars += 1; + if c.high > max_price_in_trade { max_price_in_trade = c.high; } + + let is_eod = hm >= 1520 && hm <= 1530 && c.time_str.ends_with("1520"); + + let mut exit_reason = ""; + let mut exit_price = 0.0; + + let sl_line = buy_price * (1.0 - params.sl_pct); + let tp_line = buy_price * (1.0 + params.tp_pct); + + if is_eod || hm >= 1530 { + exit_reason = "์žฅ๋งˆ๊ฐ์ฒญ์‚ฐ"; + exit_price = c.close; + } else if c.high >= tp_line { + exit_reason = "์ต์ ˆ"; + exit_price = tp_line; + } else { + let shoulder_armed = max_price_in_trade >= buy_price * (1.0 + params.shoulder_min_high); + let shoulder_line = if shoulder_armed && params.shoulder_cut_pct > 0.0 { + max_price_in_trade * (1.0 - params.shoulder_cut_pct) + } else { 0.0 }; + + if shoulder_armed && c.low <= shoulder_line { + exit_reason = "์–ด๊นจ์ปท"; + exit_price = shoulder_line; + } else if c.low <= sl_line { + exit_reason = "์†์ ˆ"; + exit_price = sl_line; + } else { + if params.trail_pct > 0.0 && max_price_in_trade > buy_price { + let trail_arm_line = buy_price * (1.0 + params.trail_arm_pct); + if params.trail_arm_pct <= 0.0 || max_price_in_trade >= trail_arm_line { + let trail_line = max_price_in_trade * (1.0 - params.trail_pct); + if c.low <= trail_line { + exit_reason = "ํŠธ๋ ˆ์ผ์ปท"; + exit_price = trail_line; + } + } + } + } + } + + if exit_reason.is_empty() && params.max_hold_bars > 0 && hold_bars >= params.max_hold_bars { + exit_reason = "์‹œ๊ฐ„์ปท"; + exit_price = c.close; + } + + let drop_pct = if buy_price > 0.0 { (buy_price - c.low) / buy_price } else { 0.0 }; + if exit_reason.is_empty() && drop_pct >= params.min_drop_pct_for_loss_cut { + exit_reason = "๊ธˆ์•ก์†์‹ค์ปท"; + exit_price = c.low; + } + + if !exit_reason.is_empty() { + let pnl = (exit_price - buy_price) / buy_price; + trades.push(TailTrade { + code: code.clone(), buy_time: buy_time.clone(), sell_time: c.time_str.clone(), + buy_price, sell_price: exit_price, pnl_pct: pnl * 100.0, reason: exit_reason.to_string(), + max_price: max_price_in_trade, rsi_entry + }); + in_position = false; + last_exit_mins = current_mins; + } + } else { + // ๋งค์ˆ˜ ํŒ๋‹จ + if hm < params.time_start_hm || hm >= params.time_end_hm { continue; } + if current_mins - last_exit_mins < params.cooldown_min as i64 { continue; } + if daily_cnt >= params.max_daily { continue; } + if c.close < params.min_price { continue; } + + if !params.skip_hts_scan_dupes { + if c.rsi > params.rsi_limit { continue; } + let high_low = c.high - c.low; + if high_low <= 0.0 { continue; } + + let drop_pct = (c.open - c.low) / c.open; + if drop_pct < params.drop_pct_min { continue; } + + let recovery = (c.close - c.low) / high_low; + if recovery < params.tail_recovery_min { continue; } + + let tail_len = c.close.min(c.open) - c.low; + let tail_pct = tail_len / c.close; + if tail_pct < params.tail_pct_min { continue; } + + // ๋ง์น˜ํ˜• ํŒจํ„ด ๊ฒ€์‚ฌ (lookback 3 ์ง€์›) + if params.pattern_hammer { + let lookback = 3; + let start_idx = if i >= lookback { i - lookback } else { 0 }; + let mut found_hammer = false; + for j in start_idx..=i { + let c_j = &candles[j]; + let body_top = c_j.open.max(c_j.close); + let body_bot = c_j.open.min(c_j.close); + let body_len = if body_top > body_bot { body_top - body_bot } else { 1.0 }; + let tail_len_body = if c_j.low > 0.0 { body_bot - c_j.low } else { 0.0 }; + let tail_ratio = tail_len_body / body_len; + if tail_ratio >= params.tail_ratio_min { + found_hammer = true; + break; + } + } + if !found_hammer { continue; } + } + } + + in_position = true; + // align ๋ชจ๋“œ ํ‰๋‚ด: ๋‹ค์Œ ๋ด‰ ์‹œ๊ฐ€. ๋‹ค์Œ ๋ด‰์ด ์—†์œผ๋ฉด ํ˜„์žฌ ๋ด‰ ์ข…๊ฐ€ + if i + 1 < candles.len() { + buy_price = candles[i+1].open; + buy_time = candles[i+1].time_str.clone(); + } else { + buy_price = c.close; + buy_time = c.time_str.clone(); + } + max_price_in_trade = buy_price; + hold_bars = 0; + daily_cnt += 1; + rsi_entry = c.rsi; + } + } + trades + }) + .collect(); + + Ok(all_trades) + }) +} diff --git a/kis_rust_src/src/updown_box.rs b/kis_rust_src/src/updown_box.rs new file mode 100644 index 0000000..6d9c29d --- /dev/null +++ b/kis_rust_src/src/updown_box.rs @@ -0,0 +1,202 @@ +use pyo3::prelude::*; +use serde::{Deserialize, Serialize}; + +#[pyclass] +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct BoxParams { + #[pyo3(get, set)] + pub lookback_bars: usize, + #[pyo3(get, set)] + pub range_max_pct: f64, + #[pyo3(get, set)] + pub bb_period: usize, + #[pyo3(get, set)] + pub bb_std: f64, + #[pyo3(get, set)] + pub bb_bw_max: f64, + #[pyo3(get, set)] + pub ma_period: usize, + #[pyo3(get, set)] + pub ma_slope_tol_pct: f64, + #[pyo3(get, set)] + pub stop_loss_pct: f64, + #[pyo3(get, set)] + pub tp_pct: f64, + #[pyo3(get, set)] + pub max_hold_bars: usize, +} + +#[pymethods] +impl BoxParams { + #[new] + #[allow(clippy::too_many_arguments)] + pub fn new( + lookback_bars: usize, range_max_pct: f64, bb_period: usize, bb_std: f64, bb_bw_max: f64, + ma_period: usize, ma_slope_tol_pct: f64, stop_loss_pct: f64, tp_pct: f64, max_hold_bars: usize + ) -> Self { + Self { + lookback_bars, range_max_pct, bb_period, bb_std, bb_bw_max, + ma_period, ma_slope_tol_pct, stop_loss_pct, tp_pct, max_hold_bars + } + } +} + +use crate::tail::CandleData; // CandleData ๊ตฌ์กฐ์ฒด ์žฌ์‚ฌ์šฉ + +#[pyclass] +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct BoxTrade { + #[pyo3(get, set)] + pub code: String, + #[pyo3(get, set)] + pub buy_time: String, + #[pyo3(get, set)] + pub sell_time: String, + #[pyo3(get, set)] + pub buy_price: f64, + #[pyo3(get, set)] + pub sell_price: f64, + #[pyo3(get, set)] + pub pnl_pct: f64, + #[pyo3(get, set)] + pub reason: String, +} + +/// ๋‹จ์ˆœํ™”๋œ Box ๋ฐฑํ…Œ์ŠคํŠธ Rust ๊ตฌํ˜„ (์‹คํ—˜์šฉ) +#[pyfunction] +pub fn run_box_backtest_fast(target_code: &str, candles: Vec, params: &BoxParams) -> PyResult> { + let mut trades = Vec::new(); + let mut in_position = false; + let mut buy_price = 0.0; + let mut buy_time = String::new(); + let mut hold_bars = 0; + + // ๋‹จ์ˆœ ๋ฌด์ง€์„ฑ ๋ฐ•์Šค ๋งค๋งค ์‹œ๋ฎฌ๋ ˆ์ด์…˜: + // ์•ž์ชฝ lookback_bars ๋™์•ˆ ๊ณ ์ /์ €์  ์ฐจ์ด๊ฐ€ range_max_pct ์ด๋‚ด์ด๋ฉด ๋งค์ˆ˜ + for i in params.lookback_bars..candles.len() { + if in_position { + hold_bars += 1; + let c = &candles[i]; + + let mut exit_reason = ""; + let mut exit_price = 0.0; + + let sl_line = buy_price * (1.0 - params.stop_loss_pct / 100.0); + let tp_line = buy_price * (1.0 + params.tp_pct / 100.0); + + if c.high >= tp_line { + exit_reason = "์ต์ ˆ(Rust)"; + exit_price = tp_line; + } else if c.low <= sl_line { + exit_reason = "์†์ ˆ(Rust)"; + exit_price = sl_line; + } else if hold_bars >= params.max_hold_bars { + exit_reason = "์‹œ๊ฐ„์ปท(Rust)"; + exit_price = c.close; + } + + if !exit_reason.is_empty() { + let pnl = (exit_price - buy_price) / buy_price; + trades.push(BoxTrade { + code: target_code.to_string(), buy_time: buy_time.clone(), sell_time: c.time_str.clone(), + buy_price, sell_price: exit_price, pnl_pct: pnl * 100.0, reason: exit_reason.to_string() + }); + in_position = false; + } + } else { + // ๋งค์ˆ˜ ์กฐ๊ฑด ํ‰๊ฐ€ + let mut min_val = 99999999.0_f64; + let mut max_val = 0.0_f64; + for j in i - params.lookback_bars..i { + let c = &candles[j]; + if c.low < min_val { min_val = c.low; } + if c.high > max_val { max_val = c.high; } + } + + if min_val > 0.0 { + let range_pct = (max_val - min_val) / min_val * 100.0; + if range_pct <= params.range_max_pct { + // ๋ฐ•์Šค๊ถŒ ์กฐ๊ฑด ๋งŒ์กฑ (๊ทผ์‚ฌ) -> ๋‹ค์Œ๋ด‰ ์‹œ๊ฐ€์— ์ง„์ž… + let c = &candles[i]; + in_position = true; + buy_price = c.open; + buy_time = c.time_str.clone(); + hold_bars = 0; + } + } + } + } + + Ok(trades) +} + +#[pyfunction] +pub fn run_engine_trial_box(session_id: String, params: BoxParams) -> PyResult> { + use crate::session_manager::SESSIONS; + let sessions = SESSIONS.read().unwrap(); + let session = sessions.get(&session_id).ok_or_else(|| { + pyo3::exceptions::PyValueError::new_err(format!("Session {} not found", session_id)) + })?; + + let mut all_trades = Vec::new(); + + for (code, candles) in &session.candles_by_code { + let mut in_position = false; + let mut buy_price = 0.0; + let mut buy_time = String::new(); + let mut hold_bars = 0; + + for i in params.lookback_bars..candles.len() { + if in_position { + hold_bars += 1; + let c = &candles[i]; + + let mut exit_reason = ""; + let mut exit_price = 0.0; + + let sl_line = buy_price * (1.0 - params.stop_loss_pct / 100.0); + let tp_line = buy_price * (1.0 + params.tp_pct / 100.0); + + if c.high >= tp_line { + exit_reason = "์ต์ ˆ(Rust)"; + exit_price = tp_line; + } else if c.low <= sl_line { + exit_reason = "์†์ ˆ(Rust)"; + exit_price = sl_line; + } else if hold_bars >= params.max_hold_bars { + exit_reason = "์‹œ๊ฐ„์ปท(Rust)"; + exit_price = c.close; + } + + if !exit_reason.is_empty() { + let pnl = (exit_price - buy_price) / buy_price; + all_trades.push(BoxTrade { + code: code.clone(), buy_time: buy_time.clone(), sell_time: c.time_str.clone(), + buy_price, sell_price: exit_price, pnl_pct: pnl * 100.0, reason: exit_reason.to_string() + }); + in_position = false; + } + } else { + let mut min_val = 99999999.0_f64; + let mut max_val = 0.0_f64; + for j in i - params.lookback_bars..i { + let c = &candles[j]; + if c.low < min_val { min_val = c.low; } + if c.high > max_val { max_val = c.high; } + } + + if min_val > 0.0 { + let range_pct = (max_val - min_val) / min_val * 100.0; + if range_pct <= params.range_max_pct { + let c = &candles[i]; + in_position = true; + buy_price = c.open; + buy_time = c.time_str.clone(); + hold_bars = 0; + } + } + } + } + } + Ok(all_trades) +} diff --git a/kis_trader/backtest/breakout_backtest_common.py b/kis_trader/backtest/breakout_backtest_common.py index 329dfcb..6ceba07 100644 --- a/kis_trader/backtest/breakout_backtest_common.py +++ b/kis_trader/backtest/breakout_backtest_common.py @@ -22,7 +22,7 @@ from kis_trader.backtest.backtest_portfolio_common import ( summarize_trades, ) from kis_trader.backtest.breakout_tick_loader import ( - load_breakout_ticks_by_code, + load_common_ticks_by_code, tick_coverage_stats, ) from kis_trader.engine.indicator_cache import ( @@ -444,43 +444,44 @@ def run_breakout_backtest_web_aligned( # ์ตœ์‹  ์กฐ๊ฑด๊ฒ€์ƒ‰ ์Šค๋ƒ…์ƒท์„ ๊ทธ๋Œ€๋กœ ์กฐํšŒํ•ด ์‹ค๋งค์™€ ๋™์ผ ์‹œ์  ์œ ๋‹ˆ๋ฒ„์Šค๋กœ ๋งค์ˆ˜ ํŒ์ •. # EXIT ๋””๋ฐ”์šด์Šค = CONDITION_EXIT_GRACE_SEC (์‹ค๋งค sticky/grace ์ •ํ•ฉ). if universe_by_slot is not None and breakout_backtest_universe_scan_at_enabled(engine_params): - _sk = str((meta_out or {}).get("start_key") or "") - _ek = str((meta_out or {}).get("end_key") or "") - if len(_sk) < 8 or len(_ek) < 8: - # meta_out ํ‚ค ์—†์œผ๋ฉด ์บ”๋“ค ์‹œ๊ฐ min/max ์ผ์ž๋กœ ํด๋ฐฑ - _days = [ - str(c.get("candle_time") or "")[:8] - for rows in candles_by_code.values() for c in rows - if c.get("candle_time") - ] - if _days: - _sk, _ek = min(_days), max(_days) - if len(_sk) >= 8 and len(_ek) >= 8: - from kis_trader.backtest.universe_timeline import build_universe_timeline - from kis_trader.backtest.universe_history_source import ( - resolve_backtest_universe_history_source, - ) + if "_universe_timeline" not in engine_params: + _sk = str((meta_out or {}).get("start_key") or "") + _ek = str((meta_out or {}).get("end_key") or "") + if len(_sk) < 8 or len(_ek) < 8: + # meta_out ํ‚ค ์—†์œผ๋ฉด ์บ”๋“ค ์‹œ๊ฐ min/max ์ผ์ž๋กœ ํด๋ฐฑ + _days = [ + str(c.get("candle_time") or "")[:8] + for rows in candles_by_code.values() for c in rows + if c.get("candle_time") + ] + if _days: + _sk, _ek = min(_days), max(_days) + if len(_sk) >= 8 and len(_ek) >= 8: + from kis_trader.backtest.universe_timeline import build_universe_timeline + from kis_trader.backtest.universe_history_source import ( + resolve_backtest_universe_history_source, + ) - _deb = breakout_universe_exit_debounce_sec() - # ์Šฌ๋กฏ dict(resolve_breakout_universe)์™€ ๋™์ผ ์†Œ์Šค โ€” LS ๋ผ๋ฒจ์ธ๋ฐ ํ‚ค์›€ ํƒ€์ž„๋ผ์ธ ์“ฐ๋Š” ์‚ฌ๊ณ  ๋ฐฉ์ง€ - _hs = resolve_backtest_universe_history_source( - engine_params.get("_universe_history_source") - or engine_params.get("universe_history_source") - ) - engine_params["_universe_history_source"] = _hs - _tl = build_universe_timeline( - strategy_id=BREAKOUT_STRATEGY_ID, - start_ymd=_sk[:8], end_ymd=_ek[:8], - debounce_sec=_deb, strict=False, strict_lag_minutes=0, - history_source=_hs, - ) - if _tl is not None: - engine_params["_universe_timeline"] = _tl - if meta_out is not None: - meta_out["universe_timing"] = "scan_at" - meta_out["universe_timeline_snapshots"] = _tl.snapshot_count - meta_out["universe_exit_debounce_sec"] = _deb - meta_out["universe_history_source"] = _hs + _deb = breakout_universe_exit_debounce_sec() + # ์Šฌ๋กฏ dict(resolve_breakout_universe)์™€ ๋™์ผ ์†Œ์Šค โ€” LS ๋ผ๋ฒจ์ธ๋ฐ ํ‚ค์›€ ํƒ€์ž„๋ผ์ธ ์“ฐ๋Š” ์‚ฌ๊ณ  ๋ฐฉ์ง€ + _hs = resolve_backtest_universe_history_source( + engine_params.get("_universe_history_source") + or engine_params.get("universe_history_source") + ) + engine_params["_universe_history_source"] = _hs + _tl = build_universe_timeline( + strategy_id=BREAKOUT_STRATEGY_ID, + start_ymd=_sk[:8], end_ymd=_ek[:8], + debounce_sec=_deb, strict=False, strict_lag_minutes=0, + history_source=_hs, + ) + if _tl is not None: + engine_params["_universe_timeline"] = _tl + if meta_out is not None: + meta_out["universe_timing"] = "scan_at" + meta_out["universe_timeline_snapshots"] = _tl.snapshot_count + meta_out["universe_exit_debounce_sec"] = _deb + meta_out["universe_history_source"] = _hs db_for_share = (meta_out or {}).get("db") if db_for_share and "share_denom_by_code" not in engine_params: @@ -514,8 +515,9 @@ def run_breakout_backtest_web_aligned( ) _tick_tbl = "ls_ws_ticks" else: - loaded_ticks, tick_rows = load_breakout_ticks_by_code( + loaded_ticks, tick_rows = load_common_ticks_by_code( db, start_key, end_key, set(candles_by_code.keys()), + use_spill_fallback=(str(engine_params.get("backtest_use_spill_fallback", True)).lower() in ("1", "true", "t", "y", "yes", "on")), ) _tick_tbl = "ws_ticks" tick_meta = tick_coverage_stats(candles_by_code, loaded_ticks) @@ -529,7 +531,12 @@ def run_breakout_backtest_web_aligned( _tick_tbl, ) elif loaded_ticks: - tick_meta = tick_coverage_stats(candles_by_code, loaded_ticks) + if "_tick_meta_cached" in engine_params: + tick_meta = dict(engine_params["_tick_meta_cached"]) + else: + tick_meta = tick_coverage_stats(candles_by_code, loaded_ticks) + engine_params["_tick_meta_cached"] = tick_meta + tick_meta["ws_tick_rows_loaded"] = sum( len(lst) for cm in loaded_ticks.values() for lst in cm.values() ) @@ -544,14 +551,95 @@ def run_breakout_backtest_web_aligned( from kis_trader.backtest.backtest_env_timeline import attach_backtest_env_timeline_to_params attach_backtest_env_timeline_to_params(engine_params, meta_out, BREAKOUT_STRATEGY_ID) - trades = run_breakout_backtest( - candles_by_code, - engine_params, - universe_by_slot=universe_by_slot, - ticks_by_code=loaded_ticks or None, - orderbook_by_code=ob_loaded, - program_by_code=pg_loaded, - ) + rust_session = engine_params.get("_rust_session_id") + if rust_session: + try: + import kis_rust_core + p = engine_params + def get_float(k, default=0.0): + try: return float(p.get(k, default)) + except: return float(default) + def get_int(k, default=0): + try: return int(p.get(k, default)) + except: return int(default) + def get_bool(k, default=False): + v = p.get(k, default) + if isinstance(v, bool): return v + s = str(v).lower() + if s in ("1", "true", "yes", "t", "y"): return True + return False + + bp = kis_rust_core.BreakoutParams( + get_int("lookback_min", 30), + get_int("vol_window", 10), + get_float("vol_mult", 0.0), + get_float("prev_chg_min", 0.0), + get_float("prev_chg_max", 30.0), + get_float("max_daily_chg", 25.0), + get_float("min_price", 1000.0), + get_float("min_bar_trade_value_krw", 0.0), + get_float("min_turnover_1m_pct", 0.0), + get_float("share_denom", 0.0), + get_float("confirm_margin_pct", 0.0), + get_float("body_min_pct", 0.0), + get_bool("use_ema_filter", False), + get_int("ema_fast_period", 12), + get_int("ema_slow_period", 26), + get_int("time_start_hm", 900), + get_int("time_end_hm", 1520), + abs(get_float("sl_pct", 0.02)), + get_float("tp_pct", 0.05), + get_float("trail_pct", 0.0), + get_float("trail_arm_pct", 0.0), + get_float("shoulder_min_high", 0.005), + get_float("shoulder_cut_pct", 0.003), + get_int("max_hold_bars", 0), + get_float("cooldown_min", 0.0), + get_int("max_daily", 10), + get_bool("skip_hts_scan_dupes", False), + get_int("atr_period", 14), + ) + r_trades = kis_rust_core.run_engine_trial_breakout(rust_session, bp) + trades = [ + { + "code": rt.code, + "entry_time": rt.buy_time, + "exit_time": rt.sell_time, + "entry": rt.buy_price, + "exit": rt.sell_price, + "pnl": 0, + "pnl_pct": rt.pnl_pct, + "reason": rt.reason, + "peak_price": rt.max_price, + "qty": None, + "entry_source": "rust_engine", + "ob_source": "", + "hold_min": 0, + } + for rt in r_trades + ] + except Exception as e: + print(f"[ERROR] Rust run_engine_trial_breakout failed: {e}") + trades = [] + else: + trades = run_breakout_backtest( + candles_by_code, + engine_params, + universe_by_slot=universe_by_slot, + ticks_by_code=loaded_ticks or None, + orderbook_by_code=ob_loaded, + program_by_code=pg_loaded, + ) + try: + from kis_trader.backtest.bt_post_filters import apply_bt_post_filters + trades = apply_bt_post_filters( + trades, + engine_params, + strategy="BREAKOUT" + ) + except Exception as e: + print(f"[ERROR] bt_post_filters failed: {e}") + attach_scalp_trade_pnl( trades, fee_rate=fee_rate, sell_tax=sell_tax, slip_pct=backtest_slip_pct(engine_params), diff --git a/kis_trader/backtest/breakout_tick_loader.py b/kis_trader/backtest/breakout_tick_loader.py index 08f4d59..89a983b 100644 --- a/kis_trader/backtest/breakout_tick_loader.py +++ b/kis_trader/backtest/breakout_tick_loader.py @@ -202,7 +202,7 @@ def _ingest_tick_rows( return n -def load_breakout_ticks_by_code( +def load_common_ticks_by_code( db, start_key: str, end_key: str, @@ -250,21 +250,63 @@ def load_breakout_ticks_by_code( len(codes) if codes else "ALL", ) - for chunk_s, chunk_e in chunks: + max_w = min(10, len(chunks)) if chunks else 1 + max_w = get_env_int("WS_TICK_LOAD_MAX_WORKERS", max_w) + from concurrent.futures import ThreadPoolExecutor, as_completed + + def process_chunk(chunk_s_val, chunk_e_val): + day_str = chunk_s_val[:8] + pq_path = f"/home/hoon/kis_bot/data/ticks/{mkt}/{day_str}.parquet" + + _local_out = defaultdict(dict) + _n = 0 + try: - rows = _fetch_ws_ticks_day_rows(table, mkt, chunk_s, chunk_e, codes) - n = _ingest_tick_rows(rows, out) - total += n - logger.info( - "โœ… %s day=%s rows=%s (๋ˆ„์ =%s)", - table, chunk_s[:8], n, total, - ) + import os + import time + if os.environ.get("BACKTEST_USE_RUST") == "1" and os.path.exists(pq_path): + import kis_rust_core + _st = time.time() + + codes_list = list(codes) if codes else None + tick_source = os.environ.get("TICK_SOURCE", "").strip() or None + + res = kis_rust_core.load_parquet_ticks_fast( + pq_path, chunk_s_val, chunk_e_val, codes_list, tick_source + ) + + _local_out.update(res["data"]) + _n = res["count"] + + _et = time.time() + logger.info(f"โšก [Rust Parquet ์ดˆ๊ณ ์† ๋กœ๋“œ] day={day_str} rows={_n} (Rust I/O + PyDict: {_et - _st:.3f}s)") + return chunk_s_val, chunk_e_val, _local_out, _n except Exception as e: - failed_days += 1 - logger.warning( - "%s day=%s ์กฐํšŒ ์‹คํŒจ โ€” ํ•ด๋‹น์ผ ์Šคํ‚ต: %s", - table, chunk_s[:8], e, - ) + logger.warning(f"Parquet Rust ๋กœ๋“œ ์‹คํŒจ, DB๋กœ ํด๋ฐฑ (day={day_str}): {e}") + + try: + _rows = _fetch_ws_ticks_day_rows(table, mkt, chunk_s_val, chunk_e_val, codes) + _n = _ingest_tick_rows(_rows, _local_out) + except Exception as e: + logger.warning(f"DB ๋กœ๋“œ ํด๋ฐฑ ์‹คํŒจ (day={day_str}): {e}") + + return chunk_s_val, chunk_e_val, _local_out, _n + + with ThreadPoolExecutor(max_workers=max_w) as executor: + futures = {executor.submit(process_chunk, c[0], c[1]): c for c in chunks} + for future in as_completed(futures): + c_s, c_e = futures[future] + try: + chunk_s, chunk_e, local_out, n = future.result() + for _code, mins_dict in local_out.items(): + code_bucket = out[_code] + for min_k, ticks in mins_dict.items(): + code_bucket.setdefault(min_k, []).extend(ticks) + total += n + logger.info("โœ… %s day=%s rows=%s (๋ˆ„์ =%s)", table, chunk_s[:8], n, total) + except Exception as e: + failed_days += 1 + logger.warning("%s day=%s ์กฐํšŒ ์‹คํŒจ โ€” ํ•ด๋‹น์ผ ์Šคํ‚ต: %s", table, c_s[:8], e) if total <= 0: # ws_ticks ๋น„์–ด๋„ LS 3์ฐจ๋งŒ์œผ๋กœ ์žฌ์ƒ ๊ฐ€๋Šฅ (1ยท2์ฐจ ๊ณต๋ฐฑ์ผ) @@ -592,7 +634,7 @@ def build_tick_coverage_meta_for_day( }) if not candles_by_code: return {"tick_codes_traded": len(codes_clean), "tick_bars_total": 0} - ticks_by_code, tick_rows = load_breakout_ticks_by_code( + ticks_by_code, tick_rows = load_common_ticks_by_code( db, start_key, end_key, set(candles_by_code.keys()), ) meta = tick_coverage_stats(dict(candles_by_code), ticks_by_code, bar_tf_min=tf) diff --git a/kis_trader/backtest/bt_post_filters.py b/kis_trader/backtest/bt_post_filters.py new file mode 100644 index 0000000..50926b4 --- /dev/null +++ b/kis_trader/backtest/bt_post_filters.py @@ -0,0 +1,89 @@ +import logging +from typing import Dict, Any, List, Optional +from database import TradeDB +from kis_trader.engine.whipsaw_filter import whipsaw_reject_for_signal +from kis_trader.engine.orderbook_filter import orderbook_reject_for_entry +from kis_trader.backtest.optuna_whipsaw_recommend import _parse_buy_dt, _ticks_for_buy + +logger = logging.getLogger("kis_trader.backtest.bt_post_filters") + +def apply_bt_post_filters( + trades: List[Dict[str, Any]], + engine_params: Dict[str, Any], + strategy: str, + market: str = "KR", + db: Optional[TradeDB] = None, +) -> List[Dict[str, Any]]: + """ + Rust ์—”์ง„์ด๋‚˜ ํ‹ฑ ๋กœ๋”๊ฐ€ ๋ฝ‘์•„๋‚ธ ์›์‹œ trades ๋ชฉ๋ก์— ๋Œ€ํ•ด + engine_params์— ํ˜ธ๊ฐ€/ํœฉ์˜ ์˜ต์…˜์ด ์ผœ์ ธ ์žˆ์œผ๋ฉด ์‚ฌํ›„ ํ•„ํ„ฐ๋ง์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค. + (์˜ตํˆฌ๋‚˜ 2์ฐจ ํ›„์ฒ˜๋ฆฌ์™€ 100% ๋™์ผํ•œ ์žฃ๋Œ€๋กœ ์ณ๋‚ด์–ด ์ •ํ•ฉ์„ฑ์„ ๋งž์ถฅ๋‹ˆ๋‹ค) + """ + ob_enabled = engine_params.get("_orderbook_filter_enabled", False) + whipsaw_enabled = engine_params.get("whipsaw_filter_enabled", False) + + if not ob_enabled and not whipsaw_enabled: + return trades + + if not trades: + return trades + + filtered_trades = [] + close_db = False + if db is None: + db = TradeDB() + close_db = True + + try: + for t in trades: + code = str(t.get("code") or "").strip() + raw_dt = t.get("buy_date") or t.get("buy_time") or t.get("entry_time") + try: + buy_dt = _parse_buy_dt(raw_dt) + except Exception: + continue + + current_price = float(t.get("entry") or t.get("buy_price") or 0) + rejected = False + reason = "" + + if whipsaw_enabled: + ticks = _ticks_for_buy(db, code, buy_dt, market=market) + if not ticks: + continue + sig_bar = {"close": current_price, "open": current_price} + + rej_reason, _ = whipsaw_reject_for_signal( + engine_params, + strategy=strategy, + signal_bar=sig_bar, + current_price=current_price, + ticks=ticks + ) + if rej_reason: + rejected = True + reason = f"whipsaw_reject: {rej_reason}" + + if not rejected and ob_enabled: + temp_params = dict(engine_params) + temp_params["code"] = code + temp_params["_eval_dt"] = buy_dt + + rej_reason2 = orderbook_reject_for_entry( + temp_params, + strategy, + price=current_price + ) + if rej_reason2: + rejected = True + reason = f"orderbook_reject: {rej_reason2}" + + if not rejected: + filtered_trades.append(t) + else: + pass + + return filtered_trades + finally: + if close_db: + db.close() diff --git a/kis_trader/backtest/bt_web_jobs.py b/kis_trader/backtest/bt_web_jobs.py index 1a19a1b..3b90c2b 100644 --- a/kis_trader/backtest/bt_web_jobs.py +++ b/kis_trader/backtest/bt_web_jobs.py @@ -129,6 +129,16 @@ def refresh_job(job_id: str) -> Optional[Dict[str, Any]]: m["progress"] = prog m["pid_alive"] = _pid_alive(pid) st = str(m.get("status") or "") + + logp = str(m.get("log_path") or "") + if logp and Path(logp).is_file(): + try: + with open(logp, "r", encoding="utf-8", errors="replace") as f: + import collections + q = collections.deque(f, 40) + m["log_tail"] = "".join(q) + except Exception: + m["log_tail"] = "" if st == "running": if not m["pid_alive"]: rj = m.get("result_json") diff --git a/kis_trader/backtest/ls_history_loaders.py b/kis_trader/backtest/ls_history_loaders.py index fe318a2..34e459c 100644 --- a/kis_trader/backtest/ls_history_loaders.py +++ b/kis_trader/backtest/ls_history_loaders.py @@ -189,62 +189,91 @@ def load_ls_ticks_by_code( out: Dict[str, Dict[str, List[Dict[str, Any]]]] = defaultdict(dict) total = 0 code_list = sorted(codes) if codes else None - for chunk_s, chunk_e in _iter_day_chunks_dt(s_dt, e_dt): + + chunks = list(_iter_day_chunks_dt(s_dt, e_dt)) + if not chunks: + return {}, 0 + + max_w = min(10, len(chunks)) if chunks else 1 + max_w = int(max(1, max_w)) + from concurrent.futures import ThreadPoolExecutor, as_completed + + def process_chunk(c_s, c_e): + from database import TradeDB + local_db = TradeDB() + local_out = defaultdict(dict) + n = 0 try: if code_list: - # ์ข…๋ชฉ ์ˆ˜๊ฐ€ ๋งŽ์œผ๋ฉด IN ์ ˆ โ€” ์ฒญํฌ๋‹น ํ•œ ๋ฒˆ ph = ",".join(["%s"] * len(code_list)) - rows = db.conn.execute( + rows = local_db.conn.execute( f"SELECT code, ts, price, volume, chetime FROM ls_ws_ticks " f"WHERE ts >= %s AND ts <= %s AND code IN ({ph})", - [chunk_s, chunk_e, *code_list], + [c_s, c_e, *code_list], ).fetchall() else: - rows = db.conn.execute( + rows = local_db.conn.execute( "SELECT code, ts, price, volume, chetime FROM ls_ws_ticks " "WHERE ts >= %s AND ts <= %s", - [chunk_s, chunk_e], + [c_s, c_e], ).fetchall() - except Exception as e: - logger.warning("ls_ws_ticks day=%s ์กฐํšŒ ์‹คํŒจ: %s", chunk_s[:10], e) - continue - for r in rows or []: - code = str(r["code"]).strip() - tt = _ts_to_tick_time(r.get("ts")) - che = str(r.get("chetime") or "").strip() - che_d = "".join(ch for ch in che if ch.isdigit()) - # chetime ์ด HHMMSS ์ด๋ฉด ์ˆ˜์‹  ts ๋‚ ์งœ์™€ ํ•ฉ์ณ 14์ž๋ฆฌ - if len(che_d) >= 14: - tt = che_d[:14] - elif len(che_d) >= 6 and len(tt) >= 8: - tt = (tt[:8] + che_d[-6:]).ljust(14, "0")[:14] - if len(tt) < 12: - continue - minute_key = tt[:12] - lag = None - try: - recv_raw = r.get("ts") - if isinstance(recv_raw, datetime): - recv_dt = recv_raw - else: - recv_s = str(recv_raw or "")[:19] - recv_dt = datetime.strptime(recv_s, "%Y-%m-%d %H:%M:%S") - lag_f = packet_lag_seconds(tt, now_dt=recv_dt) - if lag_f is not None: - lag = int(lag_f) - except Exception: + + for r in rows or []: + code = str(r["code"]).strip() + tt = _ts_to_tick_time(r.get("ts")) + che = str(r.get("chetime") or "").strip() + che_d = "".join(ch for ch in che if ch.isdigit()) + if len(che_d) >= 14: + tt = che_d[:14] + elif len(che_d) >= 6 and len(tt) >= 8: + tt = (tt[:8] + che_d[-6:]).ljust(14, "0")[:14] + if len(tt) < 12: + continue + minute_key = tt[:12] lag = None - tick = { - "code": code, - "tick_time": tt.ljust(14, "0")[:14], - "price": float(r.get("price") or 0), - "volume": int(float(r.get("volume") or 0)), - "source": "ls", - "_lag_sec": lag, - } - bucket = out[code].setdefault(minute_key, []) - bucket.append(tick) - total += 1 + try: + recv_raw = r.get("ts") + if isinstance(recv_raw, datetime): + recv_dt = recv_raw + else: + recv_s = str(recv_raw or "")[:19] + recv_dt = datetime.strptime(recv_s, "%Y-%m-%d %H:%M:%S") + lag_f = packet_lag_seconds(tt, now_dt=recv_dt) + if lag_f is not None: + lag = int(lag_f) + except Exception: + lag = None + tick = { + "code": code, + "tick_time": tt.ljust(14, "0")[:14], + "price": float(r.get("price") or 0), + "volume": int(float(r.get("volume") or 0)), + "source": "ls", + "_lag_sec": lag, + } + bucket = local_out[code].setdefault(minute_key, []) + bucket.append(tick) + n += 1 + except Exception as e: + logger.warning("ls_ws_ticks day=%s ์กฐํšŒ ์‹คํŒจ: %s", c_s[:10], e) + finally: + local_db.close() + return c_s, c_e, local_out, n + + with ThreadPoolExecutor(max_workers=max_w) as executor: + futures = {executor.submit(process_chunk, c[0], c[1]): c for c in chunks} + for future in as_completed(futures): + c_s, c_e = futures[future] + try: + _, _, local_out, n = future.result() + for _code, mins_dict in local_out.items(): + code_bucket = out[_code] + for min_k, ticks in mins_dict.items(): + code_bucket.setdefault(min_k, []).extend(ticks) + total += n + except Exception as e: + logger.warning("ls_ws_ticks day=%s ์Šค๋ ˆ๋“œ ์‹คํŒจ: %s", c_s[:10], e) + for _code, minutes in out.items(): for _mk, ticks in minutes.items(): ticks.sort(key=lambda t: str(t.get("tick_time") or "")) diff --git a/kis_trader/backtest/momentum_backtest_common.py b/kis_trader/backtest/momentum_backtest_common.py index ec057e5..0425c13 100644 --- a/kis_trader/backtest/momentum_backtest_common.py +++ b/kis_trader/backtest/momentum_backtest_common.py @@ -546,7 +546,11 @@ def run_momentum_backtest_web_aligned( _tick_tbl, ) elif loaded_ticks: - tick_meta = tick_coverage_stats(candles_by_code, loaded_ticks) + if "_tick_meta_cached" in p: + tick_meta = dict(p["_tick_meta_cached"]) + else: + tick_meta = tick_coverage_stats(candles_by_code, loaded_ticks) + p["_tick_meta_cached"] = tick_meta tick_meta["ws_tick_rows_loaded"] = sum( len(lst) for cm in loaded_ticks.values() for lst in cm.values() ) @@ -596,12 +600,97 @@ def run_momentum_backtest_web_aligned( ) from kis_trader.backtest.backtest_env_timeline import attach_backtest_env_timeline_to_params attach_backtest_env_timeline_to_params(p, meta_out, MOMENTUM_STRATEGY_ID) - trades = run_momentum_backtest( - candles_by_code, p, universe_by_slot=universe_by_slot, - ticks_by_code=loaded_ticks or ticks_by_code, - orderbook_by_code=ob_loaded, - program_by_code=pg_loaded, - ) + rust_session = p.get("_rust_session_id") + if rust_session: + try: + import kis_rust_core + def get_float(k, default=0.0): + try: return float(p.get(k, default)) + except: return float(default) + def get_int(k, default=0): + try: return int(p.get(k, default)) + except: return int(default) + def get_bool(k, default=False): + v = p.get(k, default) + if isinstance(v, bool): return v + s = str(v).lower() + if s in ("1", "true", "yes", "t", "y"): return True + return False + + mp = kis_rust_core.MomentumParams( + get_int("time_start_hm", 900), + get_int("time_end_hm", 1520), + get_float("cooldown_min", 0.0), + get_int("max_daily", 10), + get_float("min_price", 1000.0), + get_bool("use_defense_filters", False), + get_bool("use_high_chase_filter", False), + get_float("high_chase_thr", 1.2), + get_bool("trigger_e_confirm", False), + get_bool("trigger_require_bull_bar", False), + get_bool("use_vol_trigger", False), + get_bool("use_rsi_filter", False), + get_bool("use_rsi_max_filter", False), + get_int("rsi_period", 14), + get_float("mom_rsi_min", 30.0), + get_float("mom_rsi_max", 70.0), + get_bool("use_ema_filter", False), + get_int("ema_fast_period", 12), + get_int("ema_slow_period", 26), + get_float("e_min_chg_pct", 0.0), + get_float("mom_vol_mult", 0.0), + get_int("mom_vol_win", 10), + get_bool("skip_hts_scan_dupes", False), + abs(get_float("sl_pct", 0.02)), + get_float("tp_pct", 0.05), + get_float("trail_pct", 0.0), + get_float("trail_arm_pct", 0.0), + get_float("shoulder_min_high", 0.005), + get_float("shoulder_cut_pct", 0.003), + get_int("max_hold_bars", 0), + get_float("max_loss_krw", 200000.0), + get_float("min_drop_pct_for_loss_cut", 0.015), + ) + r_trades = kis_rust_core.run_engine_trial_momentum(rust_session, mp) + trades = [ + { + "code": rt.code, + "entry_time": rt.buy_time, + "exit_time": rt.sell_time, + "entry": rt.buy_price, + "exit": rt.sell_price, + "pnl": 0, # attach_scalp_trade_pnl ์ด ์›ํ™” ์ˆ˜์ต๊ธˆ์œผ๋กœ ์žฌ๊ณ„์‚ฐํ•˜๋„๋ก 0์œผ๋กœ ์„ธํŒ… + "pnl_pct": rt.pnl_pct, + "reason": rt.reason, + "peak_price": rt.max_price, + "rsi": rt.rsi_entry, + "qty": None, + "entry_source": "rust_engine", + "ob_source": "", + "hold_min": 0, + } + for rt in r_trades + ] + except Exception as e: + print(f"[ERROR] Rust run_engine_trial_momentum failed: {e}") + trades = [] + else: + trades = run_momentum_backtest( + candles_by_code, p, universe_by_slot=universe_by_slot, + ticks_by_code=loaded_ticks or ticks_by_code, + orderbook_by_code=ob_loaded, + program_by_code=pg_loaded, + ) + try: + from kis_trader.backtest.bt_post_filters import apply_bt_post_filters + trades = apply_bt_post_filters( + trades, + p, + strategy="MOMENTUM" + ) + except Exception as e: + print(f"[ERROR] bt_post_filters failed: {e}") + if not p.get("portfolio_mode"): _fx = float(p.get("fx_fee_rate", 0.0) or 0.0) _us = str(p.get("market") or "").strip().upper() == "US" diff --git a/kis_trader/backtest/momentum_tick_loader.py b/kis_trader/backtest/momentum_tick_loader.py index a162d68..c594c9a 100644 --- a/kis_trader/backtest/momentum_tick_loader.py +++ b/kis_trader/backtest/momentum_tick_loader.py @@ -5,11 +5,11 @@ from __future__ import annotations from kis_trader.backtest.breakout_tick_loader import ( entry_before_first_tick, first_tick_minute_key, - load_breakout_ticks_by_code, + load_common_ticks_by_code, tick_coverage_stats, ) -load_momentum_ticks_by_code = load_breakout_ticks_by_code +load_momentum_ticks_by_code = load_common_ticks_by_code __all__ = [ "load_momentum_ticks_by_code", diff --git a/kis_trader/backtest/momentum_universe_timeline.py b/kis_trader/backtest/momentum_universe_timeline.py index cc8f0cd..6d824f9 100644 --- a/kis_trader/backtest/momentum_universe_timeline.py +++ b/kis_trader/backtest/momentum_universe_timeline.py @@ -88,6 +88,8 @@ def attach_momentum_universe_timeline_to_params( return None if not momentum_backtest_universe_scan_at_enabled(params): return None + if "_momentum_universe_timeline" in params: + return params["_momentum_universe_timeline"] from kis_trader.backtest.universe_history_source import ( resolve_backtest_universe_history_source, ) diff --git a/kis_trader/backtest/optuna_breakout.py b/kis_trader/backtest/optuna_breakout.py index 15d7b04..f09f705 100644 --- a/kis_trader/backtest/optuna_breakout.py +++ b/kis_trader/backtest/optuna_breakout.py @@ -47,7 +47,7 @@ from kis_trader.backtest.param_search_cli_common import ( from kis_trader.backtest.tail_param_search import _results_dir_for_write from kis_trader.strategies.breakout import breakout_backtest_wants_tick_replay, breakout_entry_mode from kis_trader.engine.indicator_cache import attach_indicator_caches_to_params -from kis_trader.backtest.breakout_tick_loader import load_breakout_ticks_by_code +from kis_trader.backtest.breakout_tick_loader import load_common_ticks_by_code from kis_trader.utils.env import get_env_bool logger = logging.getLogger("param_search_optuna") @@ -113,6 +113,9 @@ def prepare_breakout_search_context( grid = grids[mode] base_fixed = _bo_fixed_defaults() + if os.environ.get("BACKTEST_USE_RUST") == "1": + base_fixed["use_rust"] = True + if mode == "tpe": base_fixed["skip_hts_scan_dupes"] = False apply_session_to_fixed(base_fixed, time_start_hm=time_start_hm, time_end_hm=time_end_hm) @@ -233,7 +236,7 @@ def prepare_breakout_search_context( ) logger.info("โœ… ls_ws_ticks %s๊ฑด", f"{tick_rows:,}") else: - ticks_by_code, tick_rows = load_breakout_ticks_by_code( + ticks_by_code, tick_rows = load_common_ticks_by_code( _tick_db, start_key, end_key, set(codes_candles.keys()), ) logger.info("โœ… ws_ticks %s๊ฑด", f"{tick_rows:,}") @@ -334,6 +337,24 @@ def prepare_breakout_search_context( cache_holder: Dict[str, Any] = {} attach_indicator_caches_to_params(cache_holder, codes_candles) + if universe_by_slot is not None: + from kis_trader.backtest.universe_timeline import build_universe_timeline + from kis_trader.backtest.breakout_backtest_common import BREAKOUT_STRATEGY_ID, breakout_universe_exit_debounce_sec + from kis_trader.backtest.universe_history_source import resolve_backtest_universe_history_source + _deb = breakout_universe_exit_debounce_sec() + _hs = resolve_backtest_universe_history_source(base_fixed.get("_universe_history_source") or base_fixed.get("universe_history_source")) + _tl = build_universe_timeline( + strategy_id=BREAKOUT_STRATEGY_ID, + start_ymd=start_key[:8], end_ymd=end_key[:8], + debounce_sec=_deb, strict=False, strict_lag_minutes=0, + history_source=_hs, + ) + if _tl is not None: + cache_holder["_universe_timeline"] = _tl + + if ticks_by_code: + from kis_trader.backtest.breakout_tick_loader import tick_coverage_stats + cache_holder["_tick_meta_cached"] = tick_coverage_stats(codes_candles, ticks_by_code) return BreakoutSearchContext( start=start, @@ -407,6 +428,19 @@ def run_breakout_optuna( bind_study_trials(study, n_trials=n_trials, log=logger) n_trials = clamp_optimize_n_trials(study, n_trials, log=logger) + import uuid + rust_session_id = f"optuna_break_{uuid.uuid4().hex[:8]}" + try: + import kis_rust_core + import json + candles_json = json.dumps(ctx.codes_candles) + kis_rust_core.init_backtest_session_json( + rust_session_id, + candles_json + ) + except Exception as e: + logger.warning(f"Failed to init_rust_session: {e}") + def objective(trial: optuna.Trial) -> float: if ctx.mode == "tpe": combo = suggest_breakout_params_tpe( @@ -416,6 +450,8 @@ def run_breakout_optuna( ) else: combo = suggest_breakout_params(trial, ctx.mode) + + combo["_rust_session_id"] = rust_session_id result = evaluate_breakout_param_combo( combo, base_fixed=ctx.base_fixed, diff --git a/kis_trader/backtest/optuna_common.py b/kis_trader/backtest/optuna_common.py index 7d0d791..aba6555 100644 --- a/kis_trader/backtest/optuna_common.py +++ b/kis_trader/backtest/optuna_common.py @@ -1068,7 +1068,7 @@ def build_optuna_overfit_diagnostics(data: Dict[str, Any]) -> Dict[str, Any]: "stop_atr_mult", "target_atr_mult", "atr_sl_min_pct", "atr_sl_max_pct", "atr_tp_min_pct", "atr_tp_max_pct", "rsi_threshold", "bar_chg_min_pct", "bar_chg_max_pct", "shoulder_min_high", "shoulder_cut_pct", "cooldown_min", - "max_daily", "whipsaw_enabled", "ratchet_on", "sl_pct", "tp_pct", + "max_daily", "whipsaw_filter_enabled", "ratchet_on", "sl_pct", "tp_pct", ] key_order = [] for k in prefer + prefer_extra: diff --git a/kis_trader/backtest/optuna_momentum.py b/kis_trader/backtest/optuna_momentum.py index f4adfcb..4623080 100644 --- a/kis_trader/backtest/optuna_momentum.py +++ b/kis_trader/backtest/optuna_momentum.py @@ -120,6 +120,9 @@ def prepare_momentum_search_context( grid = grids[mode] base_fixed = _mom_fixed_defaults(market=mk if mk in ("US", "KR") else "KR") + if os.environ.get("BACKTEST_USE_RUST") == "1": + base_fixed["use_rust"] = True + if mode == "tpe": # ์—ฐ์† ํƒ์ƒ‰๋„ HTS skip ์Šค์œ• ๊ธˆ์ง€ (KR=false ๊ณ ์ • / US=True ๊ณ ์ • โ€” HTS ์—†์Œ) if mk != "US": @@ -381,6 +384,20 @@ def prepare_momentum_search_context( cache_holder: Dict[str, Any] = {} attach_indicator_caches_to_params(cache_holder, codes_candles) + if universe_by_slot is not None: + from kis_trader.backtest.momentum_universe_timeline import attach_momentum_universe_timeline_to_params + # Optuna ๋ฐ˜๋ณต๋ฌธ(์ˆ˜๋ฐฑ~์ˆ˜๋งŒํšŒ) ๋งˆ๋‹ค DB๋ฅผ ์น˜๋Š” ๋ณ‘๋ชฉ์„ ์ œ๊ฑฐํ•˜๊ธฐ ์œ„ํ•ด ์ตœ์ดˆ 1ํšŒ ์ƒ์„ฑํ•˜์—ฌ ์บ์‹œ + attach_momentum_universe_timeline_to_params( + cache_holder, + start_ymd=start_key[:8], + end_ymd=end_key[:8], + use_saved_history=True, + history_source=base_fixed.get("_universe_history_source") or base_fixed.get("universe_history_source"), + ) + + if ticks_by_code: + from kis_trader.backtest.breakout_tick_loader import tick_coverage_stats + cache_holder["_tick_meta_cached"] = tick_coverage_stats(codes_candles, ticks_by_code) return MomentumSearchContext( start=start, @@ -464,6 +481,19 @@ def run_momentum_optuna( bind_study_trials(study, n_trials=n_trials, log=logger) n_trials = clamp_optimize_n_trials(study, n_trials, log=logger) + import uuid + rust_session_id = f"optuna_mome_{uuid.uuid4().hex[:8]}" + try: + import kis_rust_core + import json + candles_json = json.dumps(ctx.codes_candles) + kis_rust_core.init_backtest_session_json( + rust_session_id, + candles_json + ) + except Exception as e: + logger.warning(f"Failed to init_rust_session: {e}") + def objective(trial: optuna.Trial) -> float: if ctx.mode == "tpe": combo = suggest_momentum_params_tpe( @@ -471,6 +501,8 @@ def run_momentum_optuna( ) else: combo = suggest_momentum_params(trial, ctx.mode, market=getattr(ctx, "market", "KR") or "KR") + + combo["_rust_session_id"] = rust_session_id result = evaluate_momentum_param_combo( combo, base_fixed=ctx.base_fixed, diff --git a/kis_trader/backtest/optuna_scalping.py b/kis_trader/backtest/optuna_scalping.py index 4795bfa..2fa4a5c 100644 --- a/kis_trader/backtest/optuna_scalping.py +++ b/kis_trader/backtest/optuna_scalping.py @@ -16,7 +16,7 @@ from optuna.samplers import RandomSampler, TPESampler from database import TradeDB from kis_trader.backtest import scalping_backtest_common as sbc from kis_trader.backtest.breakout_tick_loader import ( - load_breakout_ticks_by_code, + load_common_ticks_by_code, tick_coverage_stats, ) from kis_trader.backtest.optuna_search_space import scalp_grid_axis_keys, suggest_scalp_params @@ -115,6 +115,9 @@ def prepare_scalp_search_context( grid_axes = grids[mode] base_fixed = _fixed_defaults() + if os.environ.get("BACKTEST_USE_RUST") == "1": + base_fixed["use_rust"] = True + if mode == "tpe": base_fixed["skip_hts_scan_dupes"] = False apply_session_to_fixed(base_fixed, time_start_hm=time_start_hm, time_end_hm=time_end_hm) @@ -214,7 +217,7 @@ def prepare_scalp_search_context( ) _tick_lbl = "ls_ws_ticks" else: - ticks_by_code, tick_rows = load_breakout_ticks_by_code( + ticks_by_code, tick_rows = load_common_ticks_by_code( _tick_db, start_key, end_key, set(codes_candles.keys()), ) _tick_lbl = "ws_ticks" @@ -299,6 +302,8 @@ def prepare_scalp_search_context( cache_holder: Dict[str, Any] = {} attach_indicator_caches_to_params(cache_holder, codes_candles) + if ticks_by_code and tick_backtest_meta: + cache_holder["_tick_meta_cached"] = tick_backtest_meta # ํ˜ธ๊ฐ€ยทํ”„๋กœ๊ทธ๋žจ ์Šค๋ƒ…์ƒท (ํ•„ํ„ฐ ON + ๊ทธ๋ฆฌ๋“œ ์Šค์œ•/์žฌ์ƒ์šฉ) orderbook_by_code: Dict[str, Any] = {} @@ -410,11 +415,26 @@ def run_scalp_optuna( bind_study_trials(study, n_trials=n_trials, log=logger) n_trials = clamp_optimize_n_trials(study, n_trials, log=logger) + import uuid + rust_session_id = f"optuna_scalp_{uuid.uuid4().hex[:8]}" + try: + import kis_rust_core + import json + candles_json = json.dumps(ctx.codes_candles) + kis_rust_core.init_backtest_session_json( + rust_session_id, + candles_json + ) + except Exception as e: + logger.warning(f"Failed to init_rust_session: {e}") + def objective(trial: optuna.Trial) -> float: if ctx.mode == "tpe": combo = suggest_scalp_params_tpe(trial) else: combo = suggest_scalp_params(trial, ctx.mode) + + combo["_rust_session_id"] = rust_session_id result = evaluate_scalp_param_combo( combo, base_fixed=ctx.base_fixed, diff --git a/kis_trader/backtest/optuna_scalping_tpe_space.py b/kis_trader/backtest/optuna_scalping_tpe_space.py index d9573a2..8168dc7 100644 --- a/kis_trader/backtest/optuna_scalping_tpe_space.py +++ b/kis_trader/backtest/optuna_scalping_tpe_space.py @@ -38,6 +38,8 @@ _SCALP_BASE_KEYS: List[str] = [ "vol_mult", "use_defense_filters", "require_reversal_candle", + "use_macd_cross", + "skip_hts_scan_dupes", "max_loss_krw", "min_drop_pct_for_loss_cut", "min_margin", @@ -95,8 +97,12 @@ def suggest_scalp_params_tpe(trial: optuna.Trial) -> Dict[str, Any]: combo["min_hold_sec"] = trial.suggest_int("min_hold_sec", 0, 300, step=10) # ํ™•์žฅ: 120โ†’300์ดˆ combo["max_daily"] = trial.suggest_int("max_daily", 5, 150, step=5) # ํ™•์žฅ: 10โ†’5, 100โ†’150 - combo["use_macd_cross"] = False - combo["skip_hts_scan_dupes"] = False + combo["use_macd_cross"] = trial.suggest_categorical( + "use_macd_cross", [False, True], + ) + combo["skip_hts_scan_dupes"] = trial.suggest_categorical( + "skip_hts_scan_dupes", [False, True], + ) combo.update(suggest_orderbook_entry_tpe(trial)) combo.update(suggest_whipsaw_tpe(trial)) return combo diff --git a/kis_trader/backtest/optuna_tpe_common.py b/kis_trader/backtest/optuna_tpe_common.py index 51e4715..9b49fa8 100644 --- a/kis_trader/backtest/optuna_tpe_common.py +++ b/kis_trader/backtest/optuna_tpe_common.py @@ -232,7 +232,7 @@ ORDERBOOK_TPE_AXIS_KEYS: List[str] = [ ] WHIPSAW_TPE_AXIS_KEYS: List[str] = [ - "whipsaw_enabled", + "whipsaw_filter_enabled", "whipsaw_subbar_sec", "whipsaw_lookback_sec", "whipsaw_dip_pct", @@ -314,7 +314,7 @@ def suggest_whipsaw_tpe(trial: optuna.Trial, *, force: bool = False) -> Dict[str if not force and not optuna_tpe_include_whipsaw(): return {} return { - "whipsaw_enabled": trial.suggest_categorical("whipsaw_enabled", [False, True]), + "whipsaw_filter_enabled": trial.suggest_categorical("whipsaw_filter_enabled", [False, True]), "whipsaw_subbar_sec": trial.suggest_categorical( "whipsaw_subbar_sec", [15, 30, 45, 60], ), diff --git a/kis_trader/backtest/param_search_apply_snapshot.py b/kis_trader/backtest/param_search_apply_snapshot.py index 92e7f86..1020c5b 100644 --- a/kis_trader/backtest/param_search_apply_snapshot.py +++ b/kis_trader/backtest/param_search_apply_snapshot.py @@ -270,7 +270,7 @@ def _patch_from_momentum_merged(m: Dict[str, Any]) -> Dict[str, str]: def _whipsaw_combo_to_env_patch(strategy: str, m: Dict[str, Any]) -> Dict[str, str]: """TPE/Grid merged ์˜ whipsaw_* โ†’ {STRAT}_WHIPSAW_* (๋ŒํŒŒยท๊ผฌ๋ฆฌ ์Šคํ‚ต์€ ํ˜ธ์ถœ์ธก).""" - if "whipsaw_enabled" not in m and "whipsaw_subbar_sec" not in m: + if "whipsaw_filter_enabled" not in m and "whipsaw_enabled" not in m and "whipsaw_subbar_sec" not in m: return {} from kis_trader.backtest.optuna_whipsaw_recommend import _whipsaw_env_prefix @@ -278,8 +278,10 @@ def _whipsaw_combo_to_env_patch(strategy: str, m: Dict[str, Any]) -> Dict[str, s if not pfx: return {} out: Dict[str, str] = {} - if "whipsaw_enabled" in m and m.get("whipsaw_enabled") is not None: - on = str(m.get("whipsaw_enabled")).strip().lower() in ("1", "true", "yes", "on") + + whip_val = m.get("whipsaw_filter_enabled") if "whipsaw_filter_enabled" in m else m.get("whipsaw_enabled") + if whip_val is not None: + on = str(whip_val).strip().lower() in ("1", "true", "yes", "on") out[f"{pfx}_WHIPSAW_FILTER_ENABLED"] = "true" if on else "false" if m.get("whipsaw_subbar_sec") not in (None, ""): out[f"{pfx}_WHIPSAW_SUBBAR_SEC"] = str(int(float(m["whipsaw_subbar_sec"]))) diff --git a/kis_trader/backtest/param_search_breakout.py b/kis_trader/backtest/param_search_breakout.py index 2f79d6b..abb1bf1 100644 --- a/kis_trader/backtest/param_search_breakout.py +++ b/kis_trader/backtest/param_search_breakout.py @@ -87,7 +87,7 @@ from kis_trader.backtest.param_search_pool import ( worker_shared_get, ) from kis_trader.backtest.breakout_tick_loader import ( - load_breakout_ticks_by_code, + load_common_ticks_by_code, tick_coverage_stats, ) from kis_trader.strategies.breakout import ( @@ -886,6 +886,7 @@ def evaluate_breakout_param_combo( engine_params["_ob_ask_max_mult"] = float(ui_params["ask_max_mult"]) if "ask_wall_max_qty" in ui_params and ui_params.get("ask_wall_max_qty") is not None: engine_params["_ob_ask_wall_max_qty"] = float(ui_params["ask_wall_max_qty"]) + if ui_params.get("_orderbook_filter_enabled") is not None: engine_params["_orderbook_filter_enabled"] = bool(ui_params["_orderbook_filter_enabled"]) # ์Šค๋ƒ…/๋ณธ์ฒด ํ”Œ๋ž˜๊ทธ โ€” breakout_ui_to_engine_params ๊ฐ€ ๋“œ๋กญํ•˜๋ฏ€๋กœ ์—ฌ๊ธฐ์„œ ์žฌ์ฃผ์ž… @@ -897,6 +898,8 @@ def evaluate_breakout_param_combo( ): if ui_params.get(_snap_k) is not None: engine_params[_snap_k] = bool(ui_params[_snap_k]) + if "_rust_session_id" in ui_params: + engine_params["_rust_session_id"] = ui_params["_rust_session_id"] if "skip_hts_scan_dupes" in ui_params: engine_params["skip_hts_scan_dupes"] = bool(ui_params["skip_hts_scan_dupes"]) elif "skip_hts_scan_dupes" not in engine_params: @@ -1216,7 +1219,7 @@ def run_search( end_key = (end.replace("-", "") + "2359") if end else "99991231" _tick_db = TradeDB() try: - ticks_by_code, tick_rows = load_breakout_ticks_by_code( + ticks_by_code, tick_rows = load_common_ticks_by_code( _tick_db, start_key, end_key, set(codes_candles.keys()), ) tick_backtest_meta = tick_coverage_stats(codes_candles, ticks_by_code) diff --git a/kis_trader/backtest/param_search_momentum.py b/kis_trader/backtest/param_search_momentum.py index 778db31..f50b044 100644 --- a/kis_trader/backtest/param_search_momentum.py +++ b/kis_trader/backtest/param_search_momentum.py @@ -1630,6 +1630,8 @@ def evaluate_momentum_param_combo( ui_params = dict(base_fixed) ui_params.update(combo) engine_params = _ui_to_engine_params(ui_params) + if "_rust_session_id" in ui_params: + engine_params["_rust_session_id"] = ui_params["_rust_session_id"] if cache_holder: engine_params.update(cache_holder) engine_params["slot_money"] = float(slot_money) diff --git a/kis_trader/backtest/param_search_optuna.py b/kis_trader/backtest/param_search_optuna.py index 7847357..be55c31 100644 --- a/kis_trader/backtest/param_search_optuna.py +++ b/kis_trader/backtest/param_search_optuna.py @@ -40,6 +40,13 @@ import os import signal import sys import time + +# ๋ฐฑํ…Œ์ŠคํŠธ ์‹œ KIS/ํ‚ค์›€ ๋ฐ์ดํ„ฐ ์ถฉ๋Œ์— ์˜ํ•œ ์บ”๋“ค ๋ฒ„๋ฆผ ํ˜„์ƒ(Garbage skip) ๋ฐฉ์ง€ +os.environ["BACKTEST_CANDLE_GARBAGE_OFF"] = "1" +os.environ["CANDLE_GARBAGE_FALLBACK"] = "False" +# ํŒŒ์ด์ฌ ์—”์ง„ Parquet ํ‹ฑ ๋กœ๋” ํ™œ์„ฑํ™” +os.environ["BACKTEST_USE_RUST"] = "1" + from dataclasses import dataclass, field from datetime import datetime, timedelta from typing import Any, Dict, List, Optional @@ -191,6 +198,9 @@ def prepare_tail_search_context( db = TradeDB() try: base_params = te.get_tail_defaults_from_db(db) + if os.environ.get("BACKTEST_USE_RUST") == "1": + base_params["use_rust"] = True + if time_start_hm is not None: base_params["time_start_hm"] = int(time_start_hm) if time_end_hm is not None: @@ -500,11 +510,22 @@ def run_tail_optuna( bind_study_trials(study, n_trials=n_trials, log=logger) n_trials = clamp_optimize_n_trials(study, n_trials, log=logger) + import uuid + rust_session_id = f"optuna_tail_{uuid.uuid4().hex[:8]}" + try: + from kis_trader.engine.tail_engine import init_rust_session, clear_rust_session + init_rust_session(rust_session_id, ctx.candles_by_code, ctx.ticks_by_code) + except Exception as e: + logger.warning(f"Failed to init_rust_session: {e}") + def objective(trial: optuna.Trial) -> float: if ctx.mode == "tpe": combo = suggest_tail_params_tpe(trial, entry_mode=ctx.tpe_entry_mode) else: combo = suggest_tail_params(trial, ctx.mode) + + # Rust ์„ธ์…˜ ID๋ฅผ ํŒŒ๋ผ๋ฏธํ„ฐ์— ๋„˜๊ฒจ์„œ ํ•˜์œ„์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•จ + combo["_rust_session_id"] = rust_session_id result = evaluate_tail_param_combo( combo, base_params=ctx.base_params, @@ -727,6 +748,11 @@ def run_tail_optuna( finally: # mode_combo ์‹ค์ธก์ด ticks ๊ณต์œ ๋ทฐ๋ฅผ ์“ฐ๋ฏ€๋กœ optimize ์งํ›„ unlink ๊ธˆ์ง€ release_shared_tick_store(ctx, log=logger) + try: + from kis_trader.engine.tail_engine import clear_rust_session + clear_rust_session(rust_session_id) + except Exception as e: + pass def apply_best_trial(study: optuna.Study, ctx: TailSearchContext) -> bool: @@ -906,7 +932,7 @@ def main() -> None: n_jobs = args.n_jobs if n_jobs is None: - n_jobs = get_env_int("PARAM_SEARCH_OPTUNA_N_JOBS", 1) + n_jobs = get_env_int("PARAM_SEARCH_OPTUNA_N_JOBS", 8) n_jobs = max(1, int(n_jobs)) sampler_name = args.sampler diff --git a/kis_trader/backtest/param_search_scalping.py b/kis_trader/backtest/param_search_scalping.py index 93168f0..5e4e2c5 100644 --- a/kis_trader/backtest/param_search_scalping.py +++ b/kis_trader/backtest/param_search_scalping.py @@ -96,7 +96,7 @@ from kis_trader.backtest.param_search_pool import ( worker_shared_get, ) from kis_trader.backtest.breakout_tick_loader import ( - load_breakout_ticks_by_code, + load_common_ticks_by_code, tick_coverage_stats, ) from kis_trader.utils.env import get_env_bool, get_env_float, get_env_from_db, get_env_int @@ -733,6 +733,10 @@ def _get_scalp_field_map(): "SCALP_WHIPSAW_FILTER_ENABLED", lambda v: "true" if v in (True, 1, "1", "true", "True", "on", "ON") else "false", ), + "whipsaw_filter_enabled": ( + "SCALP_WHIPSAW_FILTER_ENABLED", + lambda v: "true" if v in (True, 1, "1", "true", "True", "on", "ON") else "false", + ), "whipsaw_subbar_sec": ("SCALP_WHIPSAW_SUBBAR_SEC", lambda v: str(int(float(v)))), "whipsaw_lookback_sec": ("SCALP_WHIPSAW_LOOKBACK_SEC", lambda v: str(int(float(v)))), "whipsaw_dip_pct": ("SCALP_WHIPSAW_DIP_PCT", lambda v: str(float(v))), @@ -776,6 +780,8 @@ def evaluate_scalp_param_combo( ui_params = dict(base_fixed) ui_params.update(combo) engine_params = _ui_to_engine_params(ui_params) + if "_rust_session_id" in ui_params: + engine_params["_rust_session_id"] = ui_params["_rust_session_id"] if cache_holder: engine_params.update(cache_holder) engine_params["slot_money"] = float(slot_money) @@ -1190,7 +1196,7 @@ def run_search(start: str, end: str, mode: str, top_n: int, if sbc._scalp_backtest_wants_ticks(_ui_to_engine_params(FIXED_DEFAULTS)): _tick_db = TradeDB() try: - ticks_by_code, tick_rows = load_breakout_ticks_by_code( + ticks_by_code, tick_rows = load_common_ticks_by_code( _tick_db, start_key, end_key, set(codes_candles.keys()), ) tick_backtest_meta = tick_coverage_stats(codes_candles, ticks_by_code) diff --git a/kis_trader/backtest/range_break_backtest_common.py b/kis_trader/backtest/range_break_backtest_common.py index 2ecf079..fb0189a 100644 --- a/kis_trader/backtest/range_break_backtest_common.py +++ b/kis_trader/backtest/range_break_backtest_common.py @@ -17,7 +17,7 @@ from kis_trader.backtest.backtest_portfolio_common import ( summarize_trades, ) from kis_trader.backtest.breakout_tick_loader import ( - load_breakout_ticks_by_code, + load_common_ticks_by_code, tick_coverage_stats, ) from kis_trader.engine.range_break_engine import ( @@ -140,8 +140,9 @@ def run_range_break_backtest_web_aligned( db = ensure_meta_db(meta_out) if db and start_key and end_key: - loaded_ticks, tick_rows = load_breakout_ticks_by_code( + loaded_ticks, tick_rows = load_common_ticks_by_code( db, start_key, end_key, set(candles_by_code.keys()), + use_spill_fallback=(str(engine_params.get("backtest_use_spill_fallback", True)).lower() in ("1", "true", "t", "y", "yes", "on")), ) tick_meta = tick_coverage_stats(candles_by_code, loaded_ticks) tick_meta["ws_tick_rows_loaded"] = tick_rows diff --git a/kis_trader/backtest/results/optuna_breakout_tpe_20260904_112908.briefing.md b/kis_trader/backtest/results/optuna_breakout_tpe_20260904_112908.briefing.md new file mode 100644 index 0000000..d8bb7ea --- /dev/null +++ b/kis_trader/backtest/results/optuna_breakout_tpe_20260904_112908.briefing.md @@ -0,0 +1,49 @@ +# Optuna ๋ธŒ๋ฆฌํ•‘ โ€” ๋ŒํŒŒ (tpe) +๊ธฐ๊ฐ„: 2026-08-24 ~ 2026-08-24 (๊ฑฐ๋ž˜์ผโ‰ˆ1์ผ) ยท trials 200/200 +ํƒ์ƒ‰ ๊ฒŒ์ดํŠธ: WRโ‰ฅ0% PFโ‰ฅ0 ยท min_tradesโ‰ฅ2 | ํ›„๋ณด ๊ฒŒ์ดํŠธ: WRโ‰ฅ40% PFโ‰ฅ1 ยท min_tradesโ‰ฅ2 +- min_trades=2: **ํ•ฉ๊ฒฉ ์ธ์ • ์ตœ์†Œ ๊ฑฐ๋ž˜ ๊ฑด์ˆ˜**(ํ‘œ๋ณธ ๋ถ€์กฑยท์šฐ์—ฐ ์Šน๋ฅ  ๋ฐฉ์ง€). ์ด๋ณด๋‹ค ์ ์€ ์กฐํ•ฉ์€ ํ•™์Šต/ํ›„๋ณด ์ง‘๊ณ„์—์„œ ์ œ์™ธ๋ฉ๋‹ˆ๋‹ค. +ํ•™์Šต์šฉ ํ†ต๊ณผ 0๊ฑด ยท ์‚ฌํ›„ํ•ฉ๊ฒฉ(results_gated) 0๊ฑด + +## ๊ณผ์ ํ•ฉยท์ ์šฉ ๊ฐ€๋Šฅ๋„ (ํœด๋ฆฌ์Šคํ‹ฑ) +- **๊ณผ์ ํ•ฉ ์œ„ํ—˜ 73.0%** ยท **์ ์šฉ ๊ฐ€๋Šฅ๋„ 27.0%** ยท ํŒ์ •: **๋น„๊ถŒ์žฅ** โ€” ๊ณผ์ ํ•ฉยทํ‘œ๋ณธ๋ถ€์กฑ ์œ„ํ—˜ ๋†’์Œ โ€” ์‹ค๋งค DB ์ฆ‰์‹œ ์ ์šฉ ๋น„๊ถŒ์žฅ + - ํ‘œ๋ณธ ์žฅ์ผ: +40.0p โ€” ๊ฑฐ๋ž˜์ผโ‰ˆ1์ผ โ€” ๋‹จ์ผ ์žฅ ๊ณผ์ ํ•ฉ ์œ„ํ—˜ ์ตœ๋Œ€ + - ๊ฑฐ๋ž˜ ํ‘œ๋ณธ: +25.0p โ€” ํ†ต๊ณผ ํ›„๋ณด ์—†์Œ โ€” ์ ์šฉ ๋ถˆ๊ฐ€ + - ์Šน๋ฅ ยทPF ์ด์ƒ์น˜: +0.0p โ€” ์ด์ƒ์น˜ ์—†์Œ + - ๊ฒŒ์ดํŠธ ์ปค๋ฒ„: +8.0p โ€” ํ•™์Šตยทgated ๋ชจ๋‘ ๋น„์–ด ์žˆ์Œ + - PnL ๊ณ ์›: +0.0p โ€” ๊ณ ์› ํŒ์ • ์Šคํ‚ต +- _์ฐธ๊ณ : ๊ณผ์ ํ•ฉ%๋Š” ๊ต์ฐจ๊ฒ€์ฆ ์ ์ˆ˜๊ฐ€ ์•„๋‹ˆ๋ผ ํ‘œ๋ณธยท์ด์ƒ์น˜ยท๊ณ ์› ํœด๋ฆฌ์Šคํ‹ฑ์ž…๋‹ˆ๋‹ค. ์ ์šฉ ๊ฐ€๋Šฅ๋„%=100โˆ’๊ณผ์ ํ•ฉ์œ„ํ—˜%. DB ์ ์šฉ ๋ฒ„ํŠผ ํ™œ์„ฑ ์กฐ๊ฑด(gated PnL>0)๊ณผ๋Š” ๋ณ„๊ฐœ์ž…๋‹ˆ๋‹ค._ + +## ์ตœ์ข… ์„ ํƒ ํ›„๋ณด (๊ทœ์น™ ยท DB ์ ์šฉ ์ „ ํ™•์ธ) +- ์•„๋ž˜๋Š” **์—ญํ• ์ด ๋‹ค๋ฅธ** 4์ข… ํ›„๋ณด์ž…๋‹ˆ๋‹ค. mode Top10 1์œ„ โ‰  ์ต์ ˆ ๋Œ€ํ‘œ ยท **DB 1์ˆœ์œ„๋Š” ์‚ฌํ›„ํ•ฉ๊ฒฉ(gated)** ์ž…๋‹ˆ๋‹ค. +- mode pool: `positive` ยท scoring: `band_proximity_p25_p75` + +### ํ›„๋ณด 4์ข… +- **โ‘  ์‚ฌํ›„ํ•ฉ๊ฒฉ 1์œ„ (apply: gated)**: ์—†์Œ +- **โ‘ก ์•ˆ์ • 1์œ„ (apply: stable)**: ์—†์Œ +- **โ‘ข mode_combo (apply: mode)**: ์—†์Œ (๋ฏธ์‚ฐ์ถœยท๊ตฌ JSON) +- **โ‘ฃ mode Top10 1์œ„ (apply: consensus ยท ๋ฐด๋“œ ์ „ํ˜• trial)**: ์—†์Œ +- mode Top10 meta: pool 0๊ฑด ยท ์ถ• 0๊ฐœ + +### ์ถ”์ฒœ (์ž๋™ ยท confirm ํ•„์ˆ˜) +1. **์‚ฌํ›„ํ•ฉ๊ฒฉ 0๊ฑด โ†’ DB ์ ์šฉ ๋น„๊ถŒ์žฅ.** ํ˜„ํ–‰ DB ์œ ์ง€ + ์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑยท๊ธฐ๊ฐ„ ์žฌ๊ฒ€์ฆ. +- โš  ์•ˆ์ • ๊ฒŒ์ดํŠธ 0๊ฑด โ†’ ์•ˆ์ • Top์€ **์ ์ˆ˜์ˆœ ํด๋ฐฑ** (์•ˆ์ • ๊ฒŒ์ดํŠธ 0๊ฑด โ†’ ํ•™์Šตํ’€ ์•ˆ์ •์ ์ˆ˜์ˆœ TopN (๋งˆ์ด๋„ˆ์Šค PnL ํฌํ•จ ยท ์ƒ๋Œ€๋น„๊ต)) + +## ์ด์ „ ์žฅ์—์„œ๋Š” +- ์‹ค๋งค ๋™๊ธฐ๊ฐ„ ์ฒญ์‚ฐ 15๊ฑด ยท ์Šน๋ฅ  67% ยท ํ•ฉ์‚ฐ PnL -17,693์› (๋ฐฑํ…Œ Optuna์™€ ์ˆซ์ž ๋‹ฌ๋ผ๋„ ์ •์ƒ โ€” ๊ณ ์ŠคํŠธยท์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑ ๊ฒฝ๋กœ ์ฐจ์ด). +- ์ด ๊ธฐ๊ฐ„ ๋ฐฑํ…Œ์—์„œ๋Š” **์œ ์˜๋ฏธํ•œ ํ†ต๊ณผ ์กฐํ•ฉ์ด ๊ฑฐ์˜ ์—†์—ˆ์Šต๋‹ˆ๋‹ค.** ์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑยท์†์ ˆยท์‹œ๊ฐ„์ฐฝ์„ ๋จผ์ € ์ ๊ฒ€ํ•˜์„ธ์š” (๋ŒํŒŒ 0๊ฑด์ด๋ฉด ํŠนํžˆ). + +## ์•ž์œผ๋กœ ์žฅ์—์„œ๋Š” +- **1~2์ผ Optuna best๋ฅผ ๋ฐ”๋กœ ์‹ค๋งค์— ๋„ฃ์ง€ ๋งˆ์„ธ์š”.** ๋‹ค์ผ(โ‰ฅ5๊ฑฐ๋ž˜์ผ) ์žฌ๊ฒ€์ฆยท์›น๋ฐฑํ…Œ 1ํšŒ ํ›„ ๊ฒ€ํ† . +- ์ ์šฉ ์‹œ์—๋Š” `results_gated` ํ›„๋ณด๋งŒ. ํƒ์ƒ‰์šฉ best(objective)์™€ ๋‹ค๋ฅผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. +- ์žฅ์ด ์ข์•„์ง€๊ฑฐ๋‚˜ ๋ณ€๋™์„ฑ์ด ์ปค์ง€๋ฉด: ์†์ ˆยทํŠธ๋ ˆ์ผยท์‹œ๊ฐ„์ฐฝ์ด ๋จผ์ € ๊นจ์ง‘๋‹ˆ๋‹ค. ์Šน๋ฅ  ์ž๋ž‘๋ณด๋‹ค **์†์ ˆ์ด ์‚ด์•„ ์žˆ๋Š”์ง€**๋ฅผ ๋ณด์„ธ์š”. +- ํ˜„์žฌ ์‚ฌํ›„ํ•ฉ๊ฒฉ 0๊ฑด โ†’ ํŒŒ๋ผ๋ฏธํ„ฐ ์œ ์ง€(ํ˜„ํ–‰ DB) + ์œ ๋‹ˆ๋ฒ„์Šค/๋ฐ์ดํ„ฐ ์ ๊ฒ€์ด ์šฐ์„ ์ž…๋‹ˆ๋‹ค. + +_์ƒ์„ฑ: 2026-09-04 11:29:08 (rule)_ + +## AI ์ฝ”๋ฉ˜ํŠธ (์ด์ „ ์žฅ / ์•ž์œผ๋กœ ์žฅ) [gemini] + +## ์ด์ „ ์žฅ์—์„œ๋Š” +๋‹จ์ผ ๊ฑฐ๋ž˜์ผ(2026-08-24) ๋ฐฑํ…Œ์ŠคํŠธ ๊ฒฐ๊ณผ, ํ•™์Šต ๋ฐ ์‚ฌํ›„ํ•ฉ๊ฒฉ ์กฐํ•ฉ ๋ชจ๋‘ 0๊ฑด์ด์—ˆ์Šต๋‹ˆ๋‹ค. ์‹ค์ œ ๋งค๋งค๋Š” 15๊ฑด ์ฒญ์‚ฐ, ์Šน๋ฅ  67%์— PnL -17,693์›์„ ๊ธฐ๋กํ–ˆ์œผ๋‚˜, ๋ฐฑํ…Œ์ŠคํŠธ๋Š” ์œ ์˜๋ฏธํ•œ ์ „๋žต์„ ์ฐพ์ง€ ๋ชปํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š” 73%์˜ ์‹ฌ๊ฐํ•œ ๊ณผ์ ํ•ฉ ์œ„ํ—˜๊ณผ ํ‘œ๋ณธ ๋ถ€์กฑ์„ ๋‚˜ํƒ€๋‚ด๋ฉฐ, ์‹ค๋งค์™€ ๋ฐฑํ…Œ์ŠคํŠธ ๊ฐ„์˜ ๊ดด๋ฆฌ(๊ณ ์ŠคํŠธํผ์ง€ ๋“ฑ)๋ฅผ ๋ช…ํ™•ํžˆ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค. + +## ์•ž์œผ๋กœ ์žฅ์—์„œ๋Š” +๊ทน์‹ฌํ•œ ๊ณผ์ ํ•ฉ ์œ„ํ—˜์œผ๋กœ ์ธํ•ด, ์ด 1์ผ์น˜ Optuna ๊ฒฐ๊ณผ๋Š” ์‹ค๋งค ์ ์šฉ์„ ๊ฐ•๋ ฅํžˆ ๋น„๊ถŒ์žฅํ•ฉ๋‹ˆ๋‹ค. `์‚ฌํ›„ํ•ฉ๊ฒฉ` ํ›„๋ณด๊ฐ€ ์—†๋Š” ์ƒํƒœ์ด๋ฏ€๋กœ, `mode Top10 1์œ„` ๋˜ํ•œ ์ต์ ˆ ๋Œ€ํ‘œ๊ฐ€ ๋  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ๋‹ค์ผ ์žฌ๊ฒ€์ฆ๊ณผ ์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑยท์†์ ˆ ํŒŒ๋ผ๋ฏธํ„ฐ ์žฌ๊ฒ€ํ† ๊ฐ€ ํ•„์ˆ˜์ ์ž…๋‹ˆ๋‹ค. ์Šน๋ฅ ๋ณด๋‹ค ์†์ ˆ ๊ธฐ๋Šฅ ์œ ์ง€๊ฐ€ ๋” ์ค‘์š”ํ•˜๋ฉฐ, ํ˜„ํ–‰ DB ์œ ์ง€์™€ ๋ฐ์ดํ„ฐ ์ ๊ฒ€์ด ์šฐ์„ ์ž…๋‹ˆ๋‹ค. diff --git a/kis_trader/backtest/results/optuna_breakout_tpe_20260904_120508.briefing.md b/kis_trader/backtest/results/optuna_breakout_tpe_20260904_120508.briefing.md new file mode 100644 index 0000000..96fb1f1 --- /dev/null +++ b/kis_trader/backtest/results/optuna_breakout_tpe_20260904_120508.briefing.md @@ -0,0 +1,68 @@ +# Optuna ๋ธŒ๋ฆฌํ•‘ โ€” ๋ŒํŒŒ (tpe) +๊ธฐ๊ฐ„: 2026-08-31 ~ 2026-09-04 (๊ฑฐ๋ž˜์ผโ‰ˆ5์ผ) ยท trials 200/200 +ํƒ์ƒ‰ ๊ฒŒ์ดํŠธ: WRโ‰ฅ0% PFโ‰ฅ0 ยท min_tradesโ‰ฅ10 | ํ›„๋ณด ๊ฒŒ์ดํŠธ: WRโ‰ฅ40% PFโ‰ฅ1 ยท min_tradesโ‰ฅ10 +- min_trades=10: **ํ•ฉ๊ฒฉ ์ธ์ • ์ตœ์†Œ ๊ฑฐ๋ž˜ ๊ฑด์ˆ˜**(ํ‘œ๋ณธ ๋ถ€์กฑยท์šฐ์—ฐ ์Šน๋ฅ  ๋ฐฉ์ง€). ์ด๋ณด๋‹ค ์ ์€ ์กฐํ•ฉ์€ ํ•™์Šต/ํ›„๋ณด ์ง‘๊ณ„์—์„œ ์ œ์™ธ๋ฉ๋‹ˆ๋‹ค. +ํ•™์Šต์šฉ ํ†ต๊ณผ 180๊ฑด ยท ์‚ฌํ›„ํ•ฉ๊ฒฉ(results_gated) 17๊ฑด + +## ๊ณผ์ ํ•ฉยท์ ์šฉ ๊ฐ€๋Šฅ๋„ (ํœด๋ฆฌ์Šคํ‹ฑ) +- **๊ณผ์ ํ•ฉ ์œ„ํ—˜ 0.0%** ยท **์ ์šฉ ๊ฐ€๋Šฅ๋„ 100.0%** ยท ํŒ์ •: **์ƒ๋Œ€์ ์œผ๋กœ๋‚ฎ์Œ** โ€” ํœด๋ฆฌ์Šคํ‹ฑ์ƒ ์œ„ํ—˜ ์ƒ๋Œ€์  ๋‚ฎ์Œ โ€” ๊ทธ๋ž˜๋„ ๋‹ค์ผ ํ™•์ธ ๊ถŒ์žฅ + - ํ‘œ๋ณธ ์žฅ์ผ: +0.0p โ€” ๊ฑฐ๋ž˜์ผโ‰ˆ5์ผ โ€” ํ‘œ๋ณธ ์ผ์ˆ˜ ์ƒ๋Œ€์  ์–‘ํ˜ธ + - ๊ฑฐ๋ž˜ ํ‘œ๋ณธ: +0.0p โ€” ์ƒ์œ„ ํ›„๋ณด ๊ฑฐ๋ž˜ 13๊ฑด โ€” ์ƒ๋Œ€์  ์–‘ํ˜ธ + - ์Šน๋ฅ ยทPF ์ด์ƒ์น˜: +0.0p โ€” ์ด์ƒ์น˜ ์—†์Œ + - ๊ฒŒ์ดํŠธ ์ปค๋ฒ„: +0.0p โ€” ์‚ฌํ›„ํ•ฉ๊ฒฉ 17๊ฑด ยท stable 2๊ฑด + - PnL ๊ณ ์›: +0.0p โ€” ๊ณ ์› ๋น„์œจ 6% (1๊ฑด) +- ์ž„๊ณ„๊ฐ’ ๋ถ„ํฌ ํ‘œ๋ณธ: results_gated ์ƒ์œ„ 17๊ฑด +| ํŒŒ๋ผ๋ฏธํ„ฐ | median | p25~p75 | mode(๋น„์œจ) | +|---|---:|---|---| +| `max_daily_chg` | 50.0 | 48.0 ~ 51.0 | 50.0 (24%) | +| `vol_mult` | 2.7 | 2.2 ~ 2.9 | 2.9 (24%) | +| `vol_window` | 10.0 | 6.0 ~ 12.0 | 1 (24%) | +| `min_turnover_1m_pct` | 0.2 | 0.15 ~ 0.25 | 0.2 (24%) | +| `prev_chg_min` | 0.6 | 0.5 ~ 0.6 | 0.6 (29%) | +| `prev_chg_max` | 18.5 | 13.5 ~ 24.0 | 18.5 (24%) | +| `min_price` | 3500.0 | 2000.0 ~ 5000.0 | 5000 (35%) | +| `tp_pct` | 10.0 | 7.0 ~ 15.5 | 16.5 (12%) | +| `sl_mode` | โ€” | โ€” | fixed (100%) | +| `trail_pct` | 3.4 | 1.4 ~ 5.2 | 0.4 (12%) | +| `trail_arm_pct` | 3.7 | 3.4 ~ 4.7 | 3.7 (18%) | +| `shoulder_min_high_pct` | 3.9 | 3.3 ~ 4.8 | 3.0 (6%) | +- _์ฐธ๊ณ : ๊ณผ์ ํ•ฉ%๋Š” ๊ต์ฐจ๊ฒ€์ฆ ์ ์ˆ˜๊ฐ€ ์•„๋‹ˆ๋ผ ํ‘œ๋ณธยท์ด์ƒ์น˜ยท๊ณ ์› ํœด๋ฆฌ์Šคํ‹ฑ์ž…๋‹ˆ๋‹ค. ์ ์šฉ ๊ฐ€๋Šฅ๋„%=100โˆ’๊ณผ์ ํ•ฉ์œ„ํ—˜%. DB ์ ์šฉ ๋ฒ„ํŠผ ํ™œ์„ฑ ์กฐ๊ฑด(gated PnL>0)๊ณผ๋Š” ๋ณ„๊ฐœ์ž…๋‹ˆ๋‹ค._ + +## ์ตœ์ข… ์„ ํƒ ํ›„๋ณด (๊ทœ์น™ ยท DB ์ ์šฉ ์ „ ํ™•์ธ) +- ์•„๋ž˜๋Š” **์—ญํ• ์ด ๋‹ค๋ฅธ** 4์ข… ํ›„๋ณด์ž…๋‹ˆ๋‹ค. mode Top10 1์œ„ โ‰  ์ต์ ˆ ๋Œ€ํ‘œ ยท **DB 1์ˆœ์œ„๋Š” ์‚ฌํ›„ํ•ฉ๊ฒฉ(gated)** ์ž…๋‹ˆ๋‹ค. +- mode pool: `positive` ยท scoring: `band_proximity_p25_p75` + +### ํ›„๋ณด 4์ข… +- **โ‘  ์‚ฌํ›„ํ•ฉ๊ฒฉ 1์œ„ (apply: gated)** (trial #118): PnL 23,292์› ยท WR 92.3% ยท PF 4.04 ยท ๊ฑฐ๋ž˜ 13๊ฑด ยท ์•ˆ์ •์ ์ˆ˜ -40 ยท ์ต์ ˆ7.0% ์†์ ˆ5.1% +- **โ‘ก ์•ˆ์ • 1์œ„ (apply: stable)** (trial #118): PnL 23,292์› ยท WR 92.3% ยท PF 4.04 ยท ๊ฑฐ๋ž˜ 13๊ฑด ยท ์•ˆ์ •์ ์ˆ˜ -40 ยท ์ต์ ˆ7.0% ์†์ ˆ5.1% +- **โ‘ข mode_combo (apply: mode)** (trial ์—†์Œ(์กฐ๋ฆฝ)): PnL 586์› ยท WR 44.4% ยท PF 1.02 ยท ๊ฑฐ๋ž˜ 9๊ฑด ยท ์•ˆ์ •์ ์ˆ˜ -12986 ยท ์ต์ ˆ8.5% ์†์ ˆ3.6% ยท tp ์ตœ๋นˆ 8.5% (3/22) +- **โ‘ฃ mode Top10 1์œ„ (apply: consensus ยท ๋ฐด๋“œ ์ „ํ˜• trial)** (trial #158): PnL 4,995์› ยท WR 47.4% ยท PF 1.04 ยท ๊ฑฐ๋ž˜ 19๊ฑด ยท ์•ˆ์ •์ ์ˆ˜ -38422 ยท ๊ทผ์ ‘ 96.4% (22/27์ถ• ๋ฐด๋“œ์•ˆ) ยท ์ต์ ˆ11.0% ์†์ ˆ6.0% + +- mode pool tp_pct ๋ฐด๋“œ p25~p75: **7.375~15.125%** ยท Top10 1์œ„ tp=11% โ†’ ๋ฐด๋“œ **์•ˆ** +- mode Top10 meta: pool 22๊ฑด ยท ์ถ• 27๊ฐœ + +### ์ถ”์ฒœ (์ž๋™ ยท confirm ํ•„์ˆ˜) +1. **์‹ค๋งค DB ์ ์šฉ 1์ˆœ์œ„ โ†’ โ‘  ์‚ฌํ›„ํ•ฉ๊ฒฉ 1์œ„** (`optunaApply gated`) โ€” WR/PFยทmin_trades ์‚ฌํ›„ ํ†ต๊ณผ. +2. **๋ณ€๋™์„ฑยท์†์‹ค์ผ ์ค„์ด๊ธฐ โ†’ โ‘ก ์•ˆ์ • 1์œ„** (`stable`) โ€” PnL๋ณด๋‹ค ์ผ๋ณ„ ์•ˆ์ • ์šฐ์„  ์‹œ. +3. **2์ฐจ narrowยท๋Œ€ํ‘œ ์ˆซ์ž โ†’ โ‘ข mode_combo** โ€” ์ถ•๋ณ„ ์ตœ๋นˆ ์กฐ๋ฆฝ ยท trial ๋ฒˆํ˜ธ ์—†์Œ ยท ์ต์ ˆ์€ pool ์ตœ๋นˆ๊ฐ’ ์ฐธ๊ณ . +4. **โ‘ฃ mode Top10 1์œ„** โ€” ์–‘์ˆ˜ pool ์ „ํ˜• trial(๋‹ค์ถ• ๋ฐด๋“œ ๊ทผ์ ‘). **์ต์ ˆ ํ•˜๋‚˜๋กœ ์“ฐ์ง€ ๋ง ๊ฒƒ** ยท ํ‘œ์—์„œ ใ€Œ๋ณด๊ธฐใ€โ†’ consensus apply. + +## ์ด์ „ ์žฅ์—์„œ๋Š” +- ์‹ค๋งค ๋™๊ธฐ๊ฐ„ ์ฒญ์‚ฐ 23๊ฑด ยท ์Šน๋ฅ  22% ยท ํ•ฉ์‚ฐ PnL -85,134์› (๋ฐฑํ…Œ Optuna์™€ ์ˆซ์ž ๋‹ฌ๋ผ๋„ ์ •์ƒ โ€” ๊ณ ์ŠคํŠธยท์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑ ๊ฒฝ๋กœ ์ฐจ์ด). +- ์‚ฌํ›„ํ•ฉ๊ฒฉ 1์œ„: trial #118 ยท ๊ฑฐ๋ž˜ 13๊ฑด ยท ์Šน๋ฅ  92.3% ยท PF 4.04 ยท PnL 23,292์› + +## ์•ž์œผ๋กœ ์žฅ์—์„œ๋Š” +- **1~2์ผ Optuna best๋ฅผ ๋ฐ”๋กœ ์‹ค๋งค์— ๋„ฃ์ง€ ๋งˆ์„ธ์š”.** ๋‹ค์ผ(โ‰ฅ5๊ฑฐ๋ž˜์ผ) ์žฌ๊ฒ€์ฆยท์›น๋ฐฑํ…Œ 1ํšŒ ํ›„ ๊ฒ€ํ† . +- ์ ์šฉ ์‹œ์—๋Š” `results_gated` ํ›„๋ณด๋งŒ. ํƒ์ƒ‰์šฉ best(objective)์™€ ๋‹ค๋ฅผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. +- ์žฅ์ด ์ข์•„์ง€๊ฑฐ๋‚˜ ๋ณ€๋™์„ฑ์ด ์ปค์ง€๋ฉด: ์†์ ˆยทํŠธ๋ ˆ์ผยท์‹œ๊ฐ„์ฐฝ์ด ๋จผ์ € ๊นจ์ง‘๋‹ˆ๋‹ค. ์Šน๋ฅ  ์ž๋ž‘๋ณด๋‹ค **์†์ ˆ์ด ์‚ด์•„ ์žˆ๋Š”์ง€**๋ฅผ ๋ณด์„ธ์š”. +- ์‚ฌํ›„ํ•ฉ๊ฒฉ์ด ์žˆ์–ด๋„ โ€˜๋‚ด์ผ๋„ ๊ฐ™์€ ์žฅโ€™์ด ์•„๋‹™๋‹ˆ๋‹ค. ํŽ˜์ดํผ/์†Œ์•กยท๋ชจ์˜๋กœ 1~2์ผ ๊ด€์ฐฐ ํ›„ ํ™•๋Œ€ํ•˜์„ธ์š”. + +_์ƒ์„ฑ: 2026-09-04 12:05:19 (rule)_ + +## AI ์ฝ”๋ฉ˜ํŠธ (์ด์ „ ์žฅ / ์•ž์œผ๋กœ ์žฅ) [gemini] + +## ์ด์ „ ์žฅ์—์„œ๋Š” +์‹ค์ œ ๋งค๋งค์—์„œ -85,134์›(์Šน๋ฅ  22%, 23๊ฑด)์„ ๊ธฐ๋กํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด๋ฒˆ Optuna ๋ฐฑํ…Œ์ŠคํŠธ ์‚ฌํ›„ํ•ฉ๊ฒฉ 1์œ„๋Š” PnL 23,292์›(์Šน๋ฅ  92.3%, 13๊ฑด)์œผ๋กœ ์šฐ์ˆ˜ํ–ˆ์œผ๋‚˜, ๋ฐฑํ…Œ์ŠคํŠธ์™€ ์‹ค๋งค๋Š” ๊ณ ์ŠคํŠธยท์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑ ๊ฒฝ๋กœ ์ฐจ์ด๋กœ ๊ดด๋ฆฌ๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” ๊ณผ์ ํ•ฉ ๋ฐ ํ‘œ๋ณธ ๋ถ€์กฑ ์œ„ํ—˜์„ ๋‚ดํฌํ•ฉ๋‹ˆ๋‹ค. + +## ์•ž์œผ๋กœ ์žฅ์—์„œ๋Š” +์ „๋žต ์ ์šฉ ์‹œ, 5์ผ๊ฐ„ 13๊ฑด์˜ ์งง์€ ํ‘œ๋ณธ์œผ๋กœ ๊ณผ์ ํ•ฉยทํ‘œ๋ณธ ๋ถ€์กฑ ์œ„ํ—˜์ด ๋†’์Œ์„ ๋ช…์‹ฌํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ํœด๋ฆฌ์Šคํ‹ฑ์ƒ ์œ„ํ—˜์ด ๋‚ฎ๋”๋ผ๋„, ์‹ค๋งค ๊ดด๋ฆฌ(๊ณ ์ŠคํŠธํผ์ง€)๋Š” ์ƒ์กดํ•ฉ๋‹ˆ๋‹ค. mode Top10 1์œ„๋ฅผ ์ต์ ˆ ๋Œ€ํ‘œ๋กœ ๋‹จ์ •ํ•˜์ง€ ๋งˆ์‹œ๊ณ , `results_gated` ํ›„๋ณด๋งŒ ์‹ ์ค‘ํžˆ ๊ฒ€ํ† ํ•˜์„ธ์š”. ์‹ค๋งค ์ „ ๋‹ค์ผ ์žฌ๊ฒ€์ฆ๊ณผ ํŽ˜์ดํผ/์†Œ์•ก ๋ชจ์˜๊ฐ€ ํ•„์ˆ˜์ด๋ฉฐ, ์†์ ˆ ๊ธฐ๋Šฅ์˜ ์ •์ƒ ์ž‘๋™ ์—ฌ๋ถ€๋ฅผ ๋ฐ˜๋“œ์‹œ ํ™•์ธํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ํŠน์ • ์ข…๋ชฉ ์ถ”์ฒœ์ด๋‚˜ ํ™•์ • ์ˆ˜์ต์€ ์•ฝ์†๋“œ๋ฆด ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. diff --git a/kis_trader/backtest/results/optuna_breakout_tpe_20260904_130356.briefing.md b/kis_trader/backtest/results/optuna_breakout_tpe_20260904_130356.briefing.md new file mode 100644 index 0000000..cf17cee --- /dev/null +++ b/kis_trader/backtest/results/optuna_breakout_tpe_20260904_130356.briefing.md @@ -0,0 +1,68 @@ +# Optuna ๋ธŒ๋ฆฌํ•‘ โ€” ๋ŒํŒŒ (tpe) +๊ธฐ๊ฐ„: 2026-08-31 ~ 2026-09-04 (๊ฑฐ๋ž˜์ผโ‰ˆ5์ผ) ยท trials 200/200 +ํƒ์ƒ‰ ๊ฒŒ์ดํŠธ: WRโ‰ฅ0% PFโ‰ฅ0 ยท min_tradesโ‰ฅ10 | ํ›„๋ณด ๊ฒŒ์ดํŠธ: WRโ‰ฅ40% PFโ‰ฅ1 ยท min_tradesโ‰ฅ10 +- min_trades=10: **ํ•ฉ๊ฒฉ ์ธ์ • ์ตœ์†Œ ๊ฑฐ๋ž˜ ๊ฑด์ˆ˜**(ํ‘œ๋ณธ ๋ถ€์กฑยท์šฐ์—ฐ ์Šน๋ฅ  ๋ฐฉ์ง€). ์ด๋ณด๋‹ค ์ ์€ ์กฐํ•ฉ์€ ํ•™์Šต/ํ›„๋ณด ์ง‘๊ณ„์—์„œ ์ œ์™ธ๋ฉ๋‹ˆ๋‹ค. +ํ•™์Šต์šฉ ํ†ต๊ณผ 176๊ฑด ยท ์‚ฌํ›„ํ•ฉ๊ฒฉ(results_gated) 24๊ฑด + +## ๊ณผ์ ํ•ฉยท์ ์šฉ ๊ฐ€๋Šฅ๋„ (ํœด๋ฆฌ์Šคํ‹ฑ) +- **๊ณผ์ ํ•ฉ ์œ„ํ—˜ 0.0%** ยท **์ ์šฉ ๊ฐ€๋Šฅ๋„ 100.0%** ยท ํŒ์ •: **์ƒ๋Œ€์ ์œผ๋กœ๋‚ฎ์Œ** โ€” ํœด๋ฆฌ์Šคํ‹ฑ์ƒ ์œ„ํ—˜ ์ƒ๋Œ€์  ๋‚ฎ์Œ โ€” ๊ทธ๋ž˜๋„ ๋‹ค์ผ ํ™•์ธ ๊ถŒ์žฅ + - ํ‘œ๋ณธ ์žฅ์ผ: +0.0p โ€” ๊ฑฐ๋ž˜์ผโ‰ˆ5์ผ โ€” ํ‘œ๋ณธ ์ผ์ˆ˜ ์ƒ๋Œ€์  ์–‘ํ˜ธ + - ๊ฑฐ๋ž˜ ํ‘œ๋ณธ: +0.0p โ€” ์ƒ์œ„ ํ›„๋ณด ๊ฑฐ๋ž˜ 38๊ฑด โ€” ์ƒ๋Œ€์  ์–‘ํ˜ธ + - ์Šน๋ฅ ยทPF ์ด์ƒ์น˜: +0.0p โ€” ์ด์ƒ์น˜ ์—†์Œ + - ๊ฒŒ์ดํŠธ ์ปค๋ฒ„: +0.0p โ€” ์‚ฌํ›„ํ•ฉ๊ฒฉ 24๊ฑด ยท stable 8๊ฑด + - PnL ๊ณ ์›: +0.0p โ€” ๊ณ ์› ๋น„์œจ 4% (1๊ฑด) +- ์ž„๊ณ„๊ฐ’ ๋ถ„ํฌ ํ‘œ๋ณธ: results_gated ์ƒ์œ„ 24๊ฑด +| ํŒŒ๋ผ๋ฏธํ„ฐ | median | p25~p75 | mode(๋น„์œจ) | +|---|---:|---|---| +| `max_daily_chg` | 38.5 | 33.0 ~ 46.25 | 33.0 (8%) | +| `vol_mult` | 3.45 | 3.1 ~ 4.3 | 3.1 (17%) | +| `vol_window` | 1.0 | 1.0 ~ 4.0 | 1 (54%) | +| `min_turnover_1m_pct` | 0.325 | 0.3 ~ 0.4 | 0.3 (29%) | +| `prev_chg_min` | 0.5 | 0.4 ~ 0.6 | 0.5 (33%) | +| `prev_chg_max` | 15.5 | 9.0 ~ 18.125 | 9.0 (12%) | +| `min_price` | 4000.0 | 2750.0 ~ 4500.0 | 4500 (29%) | +| `tp_pct` | 2.0 | 1.5 ~ 3.5 | 1.0 (21%) | +| `sl_mode` | โ€” | โ€” | fixed (100%) | +| `trail_pct` | 4.6 | 3.625 ~ 5.3 | 3.4 (8%) | +| `trail_arm_pct` | 3.0 | 1.65 ~ 4.4 | 4.4 (8%) | +| `shoulder_min_high_pct` | 2.0 | 1.35 ~ 3.725 | 1.1 (8%) | +- _์ฐธ๊ณ : ๊ณผ์ ํ•ฉ%๋Š” ๊ต์ฐจ๊ฒ€์ฆ ์ ์ˆ˜๊ฐ€ ์•„๋‹ˆ๋ผ ํ‘œ๋ณธยท์ด์ƒ์น˜ยท๊ณ ์› ํœด๋ฆฌ์Šคํ‹ฑ์ž…๋‹ˆ๋‹ค. ์ ์šฉ ๊ฐ€๋Šฅ๋„%=100โˆ’๊ณผ์ ํ•ฉ์œ„ํ—˜%. DB ์ ์šฉ ๋ฒ„ํŠผ ํ™œ์„ฑ ์กฐ๊ฑด(gated PnL>0)๊ณผ๋Š” ๋ณ„๊ฐœ์ž…๋‹ˆ๋‹ค._ + +## ์ตœ์ข… ์„ ํƒ ํ›„๋ณด (๊ทœ์น™ ยท DB ์ ์šฉ ์ „ ํ™•์ธ) +- ์•„๋ž˜๋Š” **์—ญํ• ์ด ๋‹ค๋ฅธ** 4์ข… ํ›„๋ณด์ž…๋‹ˆ๋‹ค. mode Top10 1์œ„ โ‰  ์ต์ ˆ ๋Œ€ํ‘œ ยท **DB 1์ˆœ์œ„๋Š” ์‚ฌํ›„ํ•ฉ๊ฒฉ(gated)** ์ž…๋‹ˆ๋‹ค. +- mode pool: `positive` ยท scoring: `band_proximity_p25_p75` + +### ํ›„๋ณด 4์ข… +- **โ‘  ์‚ฌํ›„ํ•ฉ๊ฒฉ 1์œ„ (apply: gated)** (trial #112): PnL 28,010์› ยท WR 79.0% ยท PF 1.69 ยท ๊ฑฐ๋ž˜ 38๊ฑด ยท ์•ˆ์ •์ ์ˆ˜ -3562 ยท ์ต์ ˆ1.0% ์†์ ˆ1.6% +- **โ‘ก ์•ˆ์ • 1์œ„ (apply: stable)** (trial #29): PnL 10,330์› ยท WR 68.4% ยท PF 1.45 ยท ๊ฑฐ๋ž˜ 19๊ฑด ยท ์•ˆ์ •์ ์ˆ˜ -1023 ยท ์ต์ ˆ1.0% ์†์ ˆ1.0% +- **โ‘ข mode_combo (apply: mode)** (trial ์—†์Œ(์กฐ๋ฆฝ)): PnL 22,661์› ยท WR 69.2% ยท PF 1.90 ยท ๊ฑฐ๋ž˜ 26๊ฑด ยท ์•ˆ์ •์ ์ˆ˜ -2764 ยท ์ต์ ˆ1.0% ์†์ ˆ1.7% ยท tp ์ตœ๋นˆ 1.0% (5/26) +- **โ‘ฃ mode Top10 1์œ„ (apply: consensus ยท ๋ฐด๋“œ ์ „ํ˜• trial)** (trial #88): PnL 28,985์› ยท WR 83.3% ยท PF 2.21 ยท ๊ฑฐ๋ž˜ 18๊ฑด ยท ์•ˆ์ •์ ์ˆ˜ -5507 ยท ๊ทผ์ ‘ 96.2% (21/27์ถ• ๋ฐด๋“œ์•ˆ) ยท ์ต์ ˆ1.5% ์†์ ˆ3.8% + +- mode pool tp_pct ๋ฐด๋“œ p25~p75: **1.5~3.375%** ยท Top10 1์œ„ tp=1.5% โ†’ ๋ฐด๋“œ **์•ˆ** +- mode Top10 meta: pool 26๊ฑด ยท ์ถ• 27๊ฐœ + +### ์ถ”์ฒœ (์ž๋™ ยท confirm ํ•„์ˆ˜) +1. **์‹ค๋งค DB ์ ์šฉ 1์ˆœ์œ„ โ†’ โ‘  ์‚ฌํ›„ํ•ฉ๊ฒฉ 1์œ„** (`optunaApply gated`) โ€” WR/PFยทmin_trades ์‚ฌํ›„ ํ†ต๊ณผ. +2. **๋ณ€๋™์„ฑยท์†์‹ค์ผ ์ค„์ด๊ธฐ โ†’ โ‘ก ์•ˆ์ • 1์œ„** (`stable`) โ€” PnL๋ณด๋‹ค ์ผ๋ณ„ ์•ˆ์ • ์šฐ์„  ์‹œ. +3. **2์ฐจ narrowยท๋Œ€ํ‘œ ์ˆซ์ž โ†’ โ‘ข mode_combo** โ€” ์ถ•๋ณ„ ์ตœ๋นˆ ์กฐ๋ฆฝ ยท trial ๋ฒˆํ˜ธ ์—†์Œ ยท ์ต์ ˆ์€ pool ์ตœ๋นˆ๊ฐ’ ์ฐธ๊ณ . +4. **โ‘ฃ mode Top10 1์œ„** โ€” ์–‘์ˆ˜ pool ์ „ํ˜• trial(๋‹ค์ถ• ๋ฐด๋“œ ๊ทผ์ ‘). **์ต์ ˆ ํ•˜๋‚˜๋กœ ์“ฐ์ง€ ๋ง ๊ฒƒ** ยท ํ‘œ์—์„œ ใ€Œ๋ณด๊ธฐใ€โ†’ consensus apply. + +## ์ด์ „ ์žฅ์—์„œ๋Š” +- ์‹ค๋งค ๋™๊ธฐ๊ฐ„ ์ฒญ์‚ฐ 24๊ฑด ยท ์Šน๋ฅ  25% ยท ํ•ฉ์‚ฐ PnL -78,625์› (๋ฐฑํ…Œ Optuna์™€ ์ˆซ์ž ๋‹ฌ๋ผ๋„ ์ •์ƒ โ€” ๊ณ ์ŠคํŠธยท์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑ ๊ฒฝ๋กœ ์ฐจ์ด). +- ์‚ฌํ›„ํ•ฉ๊ฒฉ 1์œ„: trial #112 ยท ๊ฑฐ๋ž˜ 38๊ฑด ยท ์Šน๋ฅ  79.0% ยท PF 1.69 ยท PnL 28,010์› + +## ์•ž์œผ๋กœ ์žฅ์—์„œ๋Š” +- **1~2์ผ Optuna best๋ฅผ ๋ฐ”๋กœ ์‹ค๋งค์— ๋„ฃ์ง€ ๋งˆ์„ธ์š”.** ๋‹ค์ผ(โ‰ฅ5๊ฑฐ๋ž˜์ผ) ์žฌ๊ฒ€์ฆยท์›น๋ฐฑํ…Œ 1ํšŒ ํ›„ ๊ฒ€ํ† . +- ์ ์šฉ ์‹œ์—๋Š” `results_gated` ํ›„๋ณด๋งŒ. ํƒ์ƒ‰์šฉ best(objective)์™€ ๋‹ค๋ฅผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. +- ์žฅ์ด ์ข์•„์ง€๊ฑฐ๋‚˜ ๋ณ€๋™์„ฑ์ด ์ปค์ง€๋ฉด: ์†์ ˆยทํŠธ๋ ˆ์ผยท์‹œ๊ฐ„์ฐฝ์ด ๋จผ์ € ๊นจ์ง‘๋‹ˆ๋‹ค. ์Šน๋ฅ  ์ž๋ž‘๋ณด๋‹ค **์†์ ˆ์ด ์‚ด์•„ ์žˆ๋Š”์ง€**๋ฅผ ๋ณด์„ธ์š”. +- ์‚ฌํ›„ํ•ฉ๊ฒฉ์ด ์žˆ์–ด๋„ โ€˜๋‚ด์ผ๋„ ๊ฐ™์€ ์žฅโ€™์ด ์•„๋‹™๋‹ˆ๋‹ค. ํŽ˜์ดํผ/์†Œ์•กยท๋ชจ์˜๋กœ 1~2์ผ ๊ด€์ฐฐ ํ›„ ํ™•๋Œ€ํ•˜์„ธ์š”. + +_์ƒ์„ฑ: 2026-09-04 13:04:03 (rule)_ + +## AI ์ฝ”๋ฉ˜ํŠธ (์ด์ „ ์žฅ / ์•ž์œผ๋กœ ์žฅ) [gemini] + +ใ€Œ์ด์ „ ์žฅ์—์„œ๋Š”ใ€ +์‹ค์ œ ๋งค๋งค์—์„œ๋Š” ๋™๊ธฐ๊ฐ„ 24๊ฑด์˜ ๊ฑฐ๋ž˜์—์„œ -78,625์›์˜ ์†์‹ค๊ณผ 25%์˜ ๋‚ฎ์€ ์Šน๋ฅ ์„ ๊ธฐ๋กํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š” Optuna ๋ฐฑํ…Œ์ŠคํŠธ ๊ฒฐ๊ณผ ์ค‘ ์‚ฌํ›„ํ•ฉ๊ฒฉ 1์œ„(trial #112)๊ฐ€ 38๊ฑด์˜ ๊ฑฐ๋ž˜์—์„œ 79.0% ์Šน๋ฅ ๊ณผ 28,010์›์˜ PnL์„ ๋ณด์ธ ๊ฒƒ๊ณผ ํฐ ๊ดด๋ฆฌ๋ฅผ ๋ณด์ž…๋‹ˆ๋‹ค. ๋ฐฑํ…Œ์ŠคํŠธ์™€ ์‹ค๋งค ๊ฐ„์˜ ๊ณ ์ŠคํŠธ ์Šฌ๋ฆฌํ”ผ์ง€ ๋“ฑ ์ฐจ์ด๋ฅผ ๋ช…์‹ฌํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. + +ใ€Œ์•ž์œผ๋กœ ์žฅ์—์„œ๋Š”ใ€ +๋‹จ 5๊ฑฐ๋ž˜์ผ์˜ ์งง์€ ๋ฐฑํ…Œ์ŠคํŠธ ๊ธฐ๊ฐ„์€ ๊ณผ์ ํ•ฉ ๋ฐ ํ‘œ๋ณธ ๋ถ€์กฑ ์œ„ํ—˜์ด ๋†’์Šต๋‹ˆ๋‹ค. Optuna ํœด๋ฆฌ์Šคํ‹ฑ์ƒ '์œ„ํ—˜ ์ƒ๋Œ€์  ๋‚ฎ์Œ'์ด๋ผ ํ•ด๋„, ์‹ค์ œ ์ ์šฉ ์‹œ ๋ฐฑํ…Œ์ŠคํŠธ์™€ ์‹ค๋งค ๊ฐ„์˜ ๊ดด๋ฆฌ๊ฐ€ ํด ์ˆ˜ ์žˆ์œผ๋‹ˆ ์ฃผ์˜ํ•˜์„ธ์š”. ํŠนํžˆ mode Top10 1์œ„๋Š” 18๊ฑด์˜ ์ ์€ ๊ฑฐ๋ž˜๋กœ ๋†’์€ PnL์„ ๋ณด์˜€์œผ๋‚˜, ์ด๋ฅผ ์ต์ ˆ ๋Œ€ํ‘œ๋กœ ๋‹จ์ •ํ•ด์„  ์•ˆ ๋ฉ๋‹ˆ๋‹ค. DB 1์ˆœ์œ„๋Š” '์‚ฌํ›„ํ•ฉ๊ฒฉ'๋œ โ‘ ๋ฒˆ ํ›„๋ณด์ž…๋‹ˆ๋‹ค. ๊ธ‰ํ•œ ์‹ค๋งค ์ ์šฉ์€ ๊ธˆํ•˜๋ฉฐ, ๋‹ค์ผ ์žฌ๊ฒ€์ฆ๊ณผ ํŽ˜์ดํผ/์†Œ์•ก ๋งค๋งค๋กœ ์ถฉ๋ถ„ํžˆ ๊ด€์ฐฐ ํ›„ ํ™•๋Œ€ํ•˜์„ธ์š”. ์–ธ์ œ๋‚˜ ์†์ ˆ ๊ด€๋ฆฌ๊ฐ€ ๋ฆฌ์Šคํฌ ๊ด€๋ฆฌ์˜ ํ•ต์‹ฌ์ž…๋‹ˆ๋‹ค. diff --git a/kis_trader/backtest/results/optuna_breakout_tpe_20260904_131921.briefing.md b/kis_trader/backtest/results/optuna_breakout_tpe_20260904_131921.briefing.md new file mode 100644 index 0000000..f8cd7fe --- /dev/null +++ b/kis_trader/backtest/results/optuna_breakout_tpe_20260904_131921.briefing.md @@ -0,0 +1,49 @@ +# Optuna ๋ธŒ๋ฆฌํ•‘ โ€” ๋ŒํŒŒ (tpe) +๊ธฐ๊ฐ„: 2026-08-31 ~ 2026-09-04 (๊ฑฐ๋ž˜์ผโ‰ˆ5์ผ) ยท trials 200/200 +ํƒ์ƒ‰ ๊ฒŒ์ดํŠธ: WRโ‰ฅ0% PFโ‰ฅ0 ยท min_tradesโ‰ฅ10 | ํ›„๋ณด ๊ฒŒ์ดํŠธ: WRโ‰ฅ40% PFโ‰ฅ1 ยท min_tradesโ‰ฅ10 +- min_trades=10: **ํ•ฉ๊ฒฉ ์ธ์ • ์ตœ์†Œ ๊ฑฐ๋ž˜ ๊ฑด์ˆ˜**(ํ‘œ๋ณธ ๋ถ€์กฑยท์šฐ์—ฐ ์Šน๋ฅ  ๋ฐฉ์ง€). ์ด๋ณด๋‹ค ์ ์€ ์กฐํ•ฉ์€ ํ•™์Šต/ํ›„๋ณด ์ง‘๊ณ„์—์„œ ์ œ์™ธ๋ฉ๋‹ˆ๋‹ค. +ํ•™์Šต์šฉ ํ†ต๊ณผ 0๊ฑด ยท ์‚ฌํ›„ํ•ฉ๊ฒฉ(results_gated) 0๊ฑด + +## ๊ณผ์ ํ•ฉยท์ ์šฉ ๊ฐ€๋Šฅ๋„ (ํœด๋ฆฌ์Šคํ‹ฑ) +- **๊ณผ์ ํ•ฉ ์œ„ํ—˜ 33.0%** ยท **์ ์šฉ ๊ฐ€๋Šฅ๋„ 67.0%** ยท ํŒ์ •: **์ƒ๋Œ€์ ์œผ๋กœ๋‚ฎ์Œ** โ€” ํœด๋ฆฌ์Šคํ‹ฑ์ƒ ์œ„ํ—˜ ์ƒ๋Œ€์  ๋‚ฎ์Œ โ€” ๊ทธ๋ž˜๋„ ๋‹ค์ผ ํ™•์ธ ๊ถŒ์žฅ + - ํ‘œ๋ณธ ์žฅ์ผ: +0.0p โ€” ๊ฑฐ๋ž˜์ผโ‰ˆ5์ผ โ€” ํ‘œ๋ณธ ์ผ์ˆ˜ ์ƒ๋Œ€์  ์–‘ํ˜ธ + - ๊ฑฐ๋ž˜ ํ‘œ๋ณธ: +25.0p โ€” ํ†ต๊ณผ ํ›„๋ณด ์—†์Œ โ€” ์ ์šฉ ๋ถˆ๊ฐ€ + - ์Šน๋ฅ ยทPF ์ด์ƒ์น˜: +0.0p โ€” ์ด์ƒ์น˜ ์—†์Œ + - ๊ฒŒ์ดํŠธ ์ปค๋ฒ„: +8.0p โ€” ํ•™์Šตยทgated ๋ชจ๋‘ ๋น„์–ด ์žˆ์Œ + - PnL ๊ณ ์›: +0.0p โ€” ๊ณ ์› ํŒ์ • ์Šคํ‚ต +- _์ฐธ๊ณ : ๊ณผ์ ํ•ฉ%๋Š” ๊ต์ฐจ๊ฒ€์ฆ ์ ์ˆ˜๊ฐ€ ์•„๋‹ˆ๋ผ ํ‘œ๋ณธยท์ด์ƒ์น˜ยท๊ณ ์› ํœด๋ฆฌ์Šคํ‹ฑ์ž…๋‹ˆ๋‹ค. ์ ์šฉ ๊ฐ€๋Šฅ๋„%=100โˆ’๊ณผ์ ํ•ฉ์œ„ํ—˜%. DB ์ ์šฉ ๋ฒ„ํŠผ ํ™œ์„ฑ ์กฐ๊ฑด(gated PnL>0)๊ณผ๋Š” ๋ณ„๊ฐœ์ž…๋‹ˆ๋‹ค._ + +## ์ตœ์ข… ์„ ํƒ ํ›„๋ณด (๊ทœ์น™ ยท DB ์ ์šฉ ์ „ ํ™•์ธ) +- ์•„๋ž˜๋Š” **์—ญํ• ์ด ๋‹ค๋ฅธ** 4์ข… ํ›„๋ณด์ž…๋‹ˆ๋‹ค. mode Top10 1์œ„ โ‰  ์ต์ ˆ ๋Œ€ํ‘œ ยท **DB 1์ˆœ์œ„๋Š” ์‚ฌํ›„ํ•ฉ๊ฒฉ(gated)** ์ž…๋‹ˆ๋‹ค. +- mode pool: `positive` ยท scoring: `band_proximity_p25_p75` + +### ํ›„๋ณด 4์ข… +- **โ‘  ์‚ฌํ›„ํ•ฉ๊ฒฉ 1์œ„ (apply: gated)**: ์—†์Œ +- **โ‘ก ์•ˆ์ • 1์œ„ (apply: stable)**: ์—†์Œ +- **โ‘ข mode_combo (apply: mode)**: ์—†์Œ (๋ฏธ์‚ฐ์ถœยท๊ตฌ JSON) +- **โ‘ฃ mode Top10 1์œ„ (apply: consensus ยท ๋ฐด๋“œ ์ „ํ˜• trial)**: ์—†์Œ +- mode Top10 meta: pool 0๊ฑด ยท ์ถ• 0๊ฐœ + +### ์ถ”์ฒœ (์ž๋™ ยท confirm ํ•„์ˆ˜) +1. **์‚ฌํ›„ํ•ฉ๊ฒฉ 0๊ฑด โ†’ DB ์ ์šฉ ๋น„๊ถŒ์žฅ.** ํ˜„ํ–‰ DB ์œ ์ง€ + ์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑยท๊ธฐ๊ฐ„ ์žฌ๊ฒ€์ฆ. +- โš  ์•ˆ์ • ๊ฒŒ์ดํŠธ 0๊ฑด โ†’ ์•ˆ์ • Top์€ **์ ์ˆ˜์ˆœ ํด๋ฐฑ** (์•ˆ์ • ๊ฒŒ์ดํŠธ 0๊ฑด โ†’ ํ•™์Šตํ’€ ์•ˆ์ •์ ์ˆ˜์ˆœ TopN (๋งˆ์ด๋„ˆ์Šค PnL ํฌํ•จ ยท ์ƒ๋Œ€๋น„๊ต)) + +## ์ด์ „ ์žฅ์—์„œ๋Š” +- ์‹ค๋งค ๋™๊ธฐ๊ฐ„ ์ฒญ์‚ฐ 25๊ฑด ยท ์Šน๋ฅ  24% ยท ํ•ฉ์‚ฐ PnL -87,351์› (๋ฐฑํ…Œ Optuna์™€ ์ˆซ์ž ๋‹ฌ๋ผ๋„ ์ •์ƒ โ€” ๊ณ ์ŠคํŠธยท์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑ ๊ฒฝ๋กœ ์ฐจ์ด). +- ์ด ๊ธฐ๊ฐ„ ๋ฐฑํ…Œ์—์„œ๋Š” **์œ ์˜๋ฏธํ•œ ํ†ต๊ณผ ์กฐํ•ฉ์ด ๊ฑฐ์˜ ์—†์—ˆ์Šต๋‹ˆ๋‹ค.** ์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑยท์†์ ˆยท์‹œ๊ฐ„์ฐฝ์„ ๋จผ์ € ์ ๊ฒ€ํ•˜์„ธ์š” (๋ŒํŒŒ 0๊ฑด์ด๋ฉด ํŠนํžˆ). + +## ์•ž์œผ๋กœ ์žฅ์—์„œ๋Š” +- **1~2์ผ Optuna best๋ฅผ ๋ฐ”๋กœ ์‹ค๋งค์— ๋„ฃ์ง€ ๋งˆ์„ธ์š”.** ๋‹ค์ผ(โ‰ฅ5๊ฑฐ๋ž˜์ผ) ์žฌ๊ฒ€์ฆยท์›น๋ฐฑํ…Œ 1ํšŒ ํ›„ ๊ฒ€ํ† . +- ์ ์šฉ ์‹œ์—๋Š” `results_gated` ํ›„๋ณด๋งŒ. ํƒ์ƒ‰์šฉ best(objective)์™€ ๋‹ค๋ฅผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. +- ์žฅ์ด ์ข์•„์ง€๊ฑฐ๋‚˜ ๋ณ€๋™์„ฑ์ด ์ปค์ง€๋ฉด: ์†์ ˆยทํŠธ๋ ˆ์ผยท์‹œ๊ฐ„์ฐฝ์ด ๋จผ์ € ๊นจ์ง‘๋‹ˆ๋‹ค. ์Šน๋ฅ  ์ž๋ž‘๋ณด๋‹ค **์†์ ˆ์ด ์‚ด์•„ ์žˆ๋Š”์ง€**๋ฅผ ๋ณด์„ธ์š”. +- ํ˜„์žฌ ์‚ฌํ›„ํ•ฉ๊ฒฉ 0๊ฑด โ†’ ํŒŒ๋ผ๋ฏธํ„ฐ ์œ ์ง€(ํ˜„ํ–‰ DB) + ์œ ๋‹ˆ๋ฒ„์Šค/๋ฐ์ดํ„ฐ ์ ๊ฒ€์ด ์šฐ์„ ์ž…๋‹ˆ๋‹ค. + +_์ƒ์„ฑ: 2026-09-04 13:19:21 (rule)_ + +## AI ์ฝ”๋ฉ˜ํŠธ (์ด์ „ ์žฅ / ์•ž์œผ๋กœ ์žฅ) [gemini] + +### ์ด์ „ ์žฅ์—์„œ๋Š” +์‹ค๋งค์—์„œ๋Š” ๋™๊ธฐ๊ฐ„ 25๊ฑด ์ฒญ์‚ฐ, ์Šน๋ฅ  24%๋กœ PnL -87,351์› ์†์‹ค์„ ๊ธฐ๋กํ–ˆ์Šต๋‹ˆ๋‹ค. ๋ฐฑํ…Œ์ŠคํŒ… ๊ฒฐ๊ณผ ๋˜ํ•œ 5์ผ์˜ ์งง์€ ๊ธฐ๊ฐ„ ๋™์•ˆ `์ตœ์†Œ ๊ฑฐ๋ž˜ ๊ฑด์ˆ˜(min_trades=10)` ์š”๊ฑด์„ ์ถฉ์กฑํ•˜๋Š” `์‚ฌํ›„ํ•ฉ๊ฒฉ` ๋ฐ `ํ•™์Šต์šฉ ํ†ต๊ณผ` ์กฐํ•ฉ์ด ๋ชจ๋‘ 0๊ฑด์ž…๋‹ˆ๋‹ค. ์ด๋Š” **ํ‘œ๋ณธ ๋ถ€์กฑ**์œผ๋กœ ์ธํ•œ ์šฐ์—ฐํ•œ ๊ฒฐ๊ณผ์ผ ๊ฐ€๋Šฅ์„ฑ์ด ๋†’์œผ๋ฉฐ, ํœด๋ฆฌ์Šคํ‹ฑ์ƒ '์ ์šฉ ๋ถˆ๊ฐ€'๋กœ ํŒ๋‹จ๋˜์–ด **๊ณผ์ ํ•ฉ** ์œ„ํ—˜์— ๋…ธ์ถœ๋  ์ˆ˜ ์žˆ์Œ์„ ๊ฒฝ๊ณ ํ•ฉ๋‹ˆ๋‹ค. + +### ์•ž์œผ๋กœ ์žฅ์—์„œ๋Š” +ํ˜„์žฌ `์‚ฌํ›„ํ•ฉ๊ฒฉ` ํ›„๋ณด๊ฐ€ 0๊ฑด์ด๋ฏ€๋กœ, **DB ์ ์šฉ์€ ๋น„๊ถŒ์žฅ**ํ•ฉ๋‹ˆ๋‹ค. `mode Top10 1์œ„`๋Š” ์ต์ ˆ ๋Œ€ํ‘œ๊ฐ€ ์•„๋‹ˆ๋ฉฐ, **์ ˆ๋Œ€ ๋ฐ”๋กœ ์‹ค๋งค์— ์ ์šฉํ•ด์„  ์•ˆ ๋ฉ๋‹ˆ๋‹ค.** ์œ ๋‹ˆ๋ฒ„์Šค, ํ‹ฑ, ์†์ ˆ, ๊ธฐ๊ฐ„ ๋“ฑ ํ˜„์žฌ ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ๋ฉด๋ฐ€ํžˆ ์žฌ๊ฒ€์ฆํ•˜์„ธ์š”. ๋ฐฑํ…Œ์ŠคํŠธ ๊ฒฐ๊ณผ์™€ ์‹ค๋งค๋Š” `๊ณ ์ŠคํŠธํผ์ง€`์™€ ๊ฐ™์€ **๊ดด๋ฆฌ**๊ฐ€ ์–ธ์ œ๋“  ๋ฐœ์ƒํ•˜๋ฉฐ, **๊ณผ์ ํ•ฉ**๋œ ์ „๋žต์€ ์œ„ํ—˜ํ•ฉ๋‹ˆ๋‹ค. ์•ˆ์ •์ ์ธ ์ˆ˜์ต์„ ์•ฝ์†๋“œ๋ฆด ์ˆ˜ ์—†์œผ๋ฉฐ, **์†์ ˆ ๋กœ์ง์˜ ๊ฑด์ „์„ฑ**์„ ํ•ญ์ƒ ์šฐ์„  ํ™•์ธํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. diff --git a/kis_trader/backtest/results/optuna_breakout_tpe_20260904_132644.briefing.md b/kis_trader/backtest/results/optuna_breakout_tpe_20260904_132644.briefing.md new file mode 100644 index 0000000..bbbb774 --- /dev/null +++ b/kis_trader/backtest/results/optuna_breakout_tpe_20260904_132644.briefing.md @@ -0,0 +1,49 @@ +# Optuna ๋ธŒ๋ฆฌํ•‘ โ€” ๋ŒํŒŒ (tpe) +๊ธฐ๊ฐ„: 2026-08-31 ~ 2026-09-04 (๊ฑฐ๋ž˜์ผโ‰ˆ5์ผ) ยท trials 200/200 +ํƒ์ƒ‰ ๊ฒŒ์ดํŠธ: WRโ‰ฅ0% PFโ‰ฅ0 ยท min_tradesโ‰ฅ10 | ํ›„๋ณด ๊ฒŒ์ดํŠธ: WRโ‰ฅ40% PFโ‰ฅ1 ยท min_tradesโ‰ฅ10 +- min_trades=10: **ํ•ฉ๊ฒฉ ์ธ์ • ์ตœ์†Œ ๊ฑฐ๋ž˜ ๊ฑด์ˆ˜**(ํ‘œ๋ณธ ๋ถ€์กฑยท์šฐ์—ฐ ์Šน๋ฅ  ๋ฐฉ์ง€). ์ด๋ณด๋‹ค ์ ์€ ์กฐํ•ฉ์€ ํ•™์Šต/ํ›„๋ณด ์ง‘๊ณ„์—์„œ ์ œ์™ธ๋ฉ๋‹ˆ๋‹ค. +ํ•™์Šต์šฉ ํ†ต๊ณผ 0๊ฑด ยท ์‚ฌํ›„ํ•ฉ๊ฒฉ(results_gated) 0๊ฑด + +## ๊ณผ์ ํ•ฉยท์ ์šฉ ๊ฐ€๋Šฅ๋„ (ํœด๋ฆฌ์Šคํ‹ฑ) +- **๊ณผ์ ํ•ฉ ์œ„ํ—˜ 33.0%** ยท **์ ์šฉ ๊ฐ€๋Šฅ๋„ 67.0%** ยท ํŒ์ •: **์ƒ๋Œ€์ ์œผ๋กœ๋‚ฎ์Œ** โ€” ํœด๋ฆฌ์Šคํ‹ฑ์ƒ ์œ„ํ—˜ ์ƒ๋Œ€์  ๋‚ฎ์Œ โ€” ๊ทธ๋ž˜๋„ ๋‹ค์ผ ํ™•์ธ ๊ถŒ์žฅ + - ํ‘œ๋ณธ ์žฅ์ผ: +0.0p โ€” ๊ฑฐ๋ž˜์ผโ‰ˆ5์ผ โ€” ํ‘œ๋ณธ ์ผ์ˆ˜ ์ƒ๋Œ€์  ์–‘ํ˜ธ + - ๊ฑฐ๋ž˜ ํ‘œ๋ณธ: +25.0p โ€” ํ†ต๊ณผ ํ›„๋ณด ์—†์Œ โ€” ์ ์šฉ ๋ถˆ๊ฐ€ + - ์Šน๋ฅ ยทPF ์ด์ƒ์น˜: +0.0p โ€” ์ด์ƒ์น˜ ์—†์Œ + - ๊ฒŒ์ดํŠธ ์ปค๋ฒ„: +8.0p โ€” ํ•™์Šตยทgated ๋ชจ๋‘ ๋น„์–ด ์žˆ์Œ + - PnL ๊ณ ์›: +0.0p โ€” ๊ณ ์› ํŒ์ • ์Šคํ‚ต +- _์ฐธ๊ณ : ๊ณผ์ ํ•ฉ%๋Š” ๊ต์ฐจ๊ฒ€์ฆ ์ ์ˆ˜๊ฐ€ ์•„๋‹ˆ๋ผ ํ‘œ๋ณธยท์ด์ƒ์น˜ยท๊ณ ์› ํœด๋ฆฌ์Šคํ‹ฑ์ž…๋‹ˆ๋‹ค. ์ ์šฉ ๊ฐ€๋Šฅ๋„%=100โˆ’๊ณผ์ ํ•ฉ์œ„ํ—˜%. DB ์ ์šฉ ๋ฒ„ํŠผ ํ™œ์„ฑ ์กฐ๊ฑด(gated PnL>0)๊ณผ๋Š” ๋ณ„๊ฐœ์ž…๋‹ˆ๋‹ค._ + +## ์ตœ์ข… ์„ ํƒ ํ›„๋ณด (๊ทœ์น™ ยท DB ์ ์šฉ ์ „ ํ™•์ธ) +- ์•„๋ž˜๋Š” **์—ญํ• ์ด ๋‹ค๋ฅธ** 4์ข… ํ›„๋ณด์ž…๋‹ˆ๋‹ค. mode Top10 1์œ„ โ‰  ์ต์ ˆ ๋Œ€ํ‘œ ยท **DB 1์ˆœ์œ„๋Š” ์‚ฌํ›„ํ•ฉ๊ฒฉ(gated)** ์ž…๋‹ˆ๋‹ค. +- mode pool: `positive` ยท scoring: `band_proximity_p25_p75` + +### ํ›„๋ณด 4์ข… +- **โ‘  ์‚ฌํ›„ํ•ฉ๊ฒฉ 1์œ„ (apply: gated)**: ์—†์Œ +- **โ‘ก ์•ˆ์ • 1์œ„ (apply: stable)**: ์—†์Œ +- **โ‘ข mode_combo (apply: mode)**: ์—†์Œ (๋ฏธ์‚ฐ์ถœยท๊ตฌ JSON) +- **โ‘ฃ mode Top10 1์œ„ (apply: consensus ยท ๋ฐด๋“œ ์ „ํ˜• trial)**: ์—†์Œ +- mode Top10 meta: pool 0๊ฑด ยท ์ถ• 0๊ฐœ + +### ์ถ”์ฒœ (์ž๋™ ยท confirm ํ•„์ˆ˜) +1. **์‚ฌํ›„ํ•ฉ๊ฒฉ 0๊ฑด โ†’ DB ์ ์šฉ ๋น„๊ถŒ์žฅ.** ํ˜„ํ–‰ DB ์œ ์ง€ + ์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑยท๊ธฐ๊ฐ„ ์žฌ๊ฒ€์ฆ. +- โš  ์•ˆ์ • ๊ฒŒ์ดํŠธ 0๊ฑด โ†’ ์•ˆ์ • Top์€ **์ ์ˆ˜์ˆœ ํด๋ฐฑ** (์•ˆ์ • ๊ฒŒ์ดํŠธ 0๊ฑด โ†’ ํ•™์Šตํ’€ ์•ˆ์ •์ ์ˆ˜์ˆœ TopN (๋งˆ์ด๋„ˆ์Šค PnL ํฌํ•จ ยท ์ƒ๋Œ€๋น„๊ต)) + +## ์ด์ „ ์žฅ์—์„œ๋Š” +- ์‹ค๋งค ๋™๊ธฐ๊ฐ„ ์ฒญ์‚ฐ 25๊ฑด ยท ์Šน๋ฅ  24% ยท ํ•ฉ์‚ฐ PnL -87,351์› (๋ฐฑํ…Œ Optuna์™€ ์ˆซ์ž ๋‹ฌ๋ผ๋„ ์ •์ƒ โ€” ๊ณ ์ŠคํŠธยท์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑ ๊ฒฝ๋กœ ์ฐจ์ด). +- ์ด ๊ธฐ๊ฐ„ ๋ฐฑํ…Œ์—์„œ๋Š” **์œ ์˜๋ฏธํ•œ ํ†ต๊ณผ ์กฐํ•ฉ์ด ๊ฑฐ์˜ ์—†์—ˆ์Šต๋‹ˆ๋‹ค.** ์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑยท์†์ ˆยท์‹œ๊ฐ„์ฐฝ์„ ๋จผ์ € ์ ๊ฒ€ํ•˜์„ธ์š” (๋ŒํŒŒ 0๊ฑด์ด๋ฉด ํŠนํžˆ). + +## ์•ž์œผ๋กœ ์žฅ์—์„œ๋Š” +- **1~2์ผ Optuna best๋ฅผ ๋ฐ”๋กœ ์‹ค๋งค์— ๋„ฃ์ง€ ๋งˆ์„ธ์š”.** ๋‹ค์ผ(โ‰ฅ5๊ฑฐ๋ž˜์ผ) ์žฌ๊ฒ€์ฆยท์›น๋ฐฑํ…Œ 1ํšŒ ํ›„ ๊ฒ€ํ† . +- ์ ์šฉ ์‹œ์—๋Š” `results_gated` ํ›„๋ณด๋งŒ. ํƒ์ƒ‰์šฉ best(objective)์™€ ๋‹ค๋ฅผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. +- ์žฅ์ด ์ข์•„์ง€๊ฑฐ๋‚˜ ๋ณ€๋™์„ฑ์ด ์ปค์ง€๋ฉด: ์†์ ˆยทํŠธ๋ ˆ์ผยท์‹œ๊ฐ„์ฐฝ์ด ๋จผ์ € ๊นจ์ง‘๋‹ˆ๋‹ค. ์Šน๋ฅ  ์ž๋ž‘๋ณด๋‹ค **์†์ ˆ์ด ์‚ด์•„ ์žˆ๋Š”์ง€**๋ฅผ ๋ณด์„ธ์š”. +- ํ˜„์žฌ ์‚ฌํ›„ํ•ฉ๊ฒฉ 0๊ฑด โ†’ ํŒŒ๋ผ๋ฏธํ„ฐ ์œ ์ง€(ํ˜„ํ–‰ DB) + ์œ ๋‹ˆ๋ฒ„์Šค/๋ฐ์ดํ„ฐ ์ ๊ฒ€์ด ์šฐ์„ ์ž…๋‹ˆ๋‹ค. + +_์ƒ์„ฑ: 2026-09-04 13:26:44 (rule)_ + +## AI ์ฝ”๋ฉ˜ํŠธ (์ด์ „ ์žฅ / ์•ž์œผ๋กœ ์žฅ) [gemini] + +**์ด์ „ ์žฅ์—์„œ๋Š”** +์‹ค์ œ ๋งค๋งค์—์„œ 25๊ฑด ์ฒญ์‚ฐ, ์Šน๋ฅ  24%, PnL -8.7๋งŒ์›์„ ๊ธฐ๋กํ–ˆ์Šต๋‹ˆ๋‹ค. ๋ฐฑํ…Œ์ŠคํŠธ๋Š” ์œ ์˜๋ฏธํ•œ ํ†ต๊ณผ ์กฐํ•ฉ์ด ์—†์–ด, ๊ณผ์ ํ•ฉยทํ‘œ๋ณธ ๋ถ€์กฑ ์œ„ํ—˜์ด ๋†’๊ณ  ์‹ค๋งค ๊ดด๋ฆฌ(๊ณ ์ŠคํŠธํผ์ง€ ๋“ฑ)๋„ ํ™•์ธ๋ฉ๋‹ˆ๋‹ค. + +**์•ž์œผ๋กœ ์žฅ์—์„œ๋Š”** +๋‹จ๊ธฐ Optuna ๊ฒฐ๊ณผ๋ฅผ ๋ฐ”๋กœ ์‹ค๋งค์— ์ ์šฉ ๋งˆ์‹ญ์‹œ์˜ค. ํŠนํžˆ ์‚ฌํ›„ํ•ฉ๊ฒฉ(gated) ํ›„๋ณด 0๊ฑด์ธ ์ง€๊ธˆ์€ ๊ณผ์ ํ•ฉยทํ‘œ๋ณธ ๋ถ€์กฑ ์œ„ํ—˜์ด ๋งค์šฐ ๋†’์Šต๋‹ˆ๋‹ค. DB 1์ˆœ์œ„๋Š” ์‚ฌํ›„ํ•ฉ๊ฒฉ์ด๋ฉฐ, mode Top10 1์œ„๋Š” ์ต์ ˆ ๋Œ€ํ‘œ๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค. ํ˜„ํ–‰ DB ์œ ์ง€ ๋ฐ ์œ ๋‹ˆ๋ฒ„์Šคยท๋ฐ์ดํ„ฐ ์žฌ์ ๊ฒ€์ด ์šฐ์„ ์ด๋ฉฐ, ์‹ค๋งค์™€ ๋ฐฑํ…Œ์ŠคํŠธ ๊ดด๋ฆฌ์— ํ•ญ์ƒ ์œ ์˜ํ•˜๋ฉฐ ์†์ ˆ ์›์น™์„ ์ตœ์šฐ์„ ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. diff --git a/kis_trader/backtest/results/optuna_breakout_tpe_20260904_133301.briefing.md b/kis_trader/backtest/results/optuna_breakout_tpe_20260904_133301.briefing.md new file mode 100644 index 0000000..48d75cd --- /dev/null +++ b/kis_trader/backtest/results/optuna_breakout_tpe_20260904_133301.briefing.md @@ -0,0 +1,49 @@ +# Optuna ๋ธŒ๋ฆฌํ•‘ โ€” ๋ŒํŒŒ (tpe) +๊ธฐ๊ฐ„: 2026-08-31 ~ 2026-09-04 (๊ฑฐ๋ž˜์ผโ‰ˆ5์ผ) ยท trials 200/200 +ํƒ์ƒ‰ ๊ฒŒ์ดํŠธ: WRโ‰ฅ0% PFโ‰ฅ0 ยท min_tradesโ‰ฅ10 | ํ›„๋ณด ๊ฒŒ์ดํŠธ: WRโ‰ฅ40% PFโ‰ฅ1 ยท min_tradesโ‰ฅ10 +- min_trades=10: **ํ•ฉ๊ฒฉ ์ธ์ • ์ตœ์†Œ ๊ฑฐ๋ž˜ ๊ฑด์ˆ˜**(ํ‘œ๋ณธ ๋ถ€์กฑยท์šฐ์—ฐ ์Šน๋ฅ  ๋ฐฉ์ง€). ์ด๋ณด๋‹ค ์ ์€ ์กฐํ•ฉ์€ ํ•™์Šต/ํ›„๋ณด ์ง‘๊ณ„์—์„œ ์ œ์™ธ๋ฉ๋‹ˆ๋‹ค. +ํ•™์Šต์šฉ ํ†ต๊ณผ 0๊ฑด ยท ์‚ฌํ›„ํ•ฉ๊ฒฉ(results_gated) 0๊ฑด + +## ๊ณผ์ ํ•ฉยท์ ์šฉ ๊ฐ€๋Šฅ๋„ (ํœด๋ฆฌ์Šคํ‹ฑ) +- **๊ณผ์ ํ•ฉ ์œ„ํ—˜ 33.0%** ยท **์ ์šฉ ๊ฐ€๋Šฅ๋„ 67.0%** ยท ํŒ์ •: **์ƒ๋Œ€์ ์œผ๋กœ๋‚ฎ์Œ** โ€” ํœด๋ฆฌ์Šคํ‹ฑ์ƒ ์œ„ํ—˜ ์ƒ๋Œ€์  ๋‚ฎ์Œ โ€” ๊ทธ๋ž˜๋„ ๋‹ค์ผ ํ™•์ธ ๊ถŒ์žฅ + - ํ‘œ๋ณธ ์žฅ์ผ: +0.0p โ€” ๊ฑฐ๋ž˜์ผโ‰ˆ5์ผ โ€” ํ‘œ๋ณธ ์ผ์ˆ˜ ์ƒ๋Œ€์  ์–‘ํ˜ธ + - ๊ฑฐ๋ž˜ ํ‘œ๋ณธ: +25.0p โ€” ํ†ต๊ณผ ํ›„๋ณด ์—†์Œ โ€” ์ ์šฉ ๋ถˆ๊ฐ€ + - ์Šน๋ฅ ยทPF ์ด์ƒ์น˜: +0.0p โ€” ์ด์ƒ์น˜ ์—†์Œ + - ๊ฒŒ์ดํŠธ ์ปค๋ฒ„: +8.0p โ€” ํ•™์Šตยทgated ๋ชจ๋‘ ๋น„์–ด ์žˆ์Œ + - PnL ๊ณ ์›: +0.0p โ€” ๊ณ ์› ํŒ์ • ์Šคํ‚ต +- _์ฐธ๊ณ : ๊ณผ์ ํ•ฉ%๋Š” ๊ต์ฐจ๊ฒ€์ฆ ์ ์ˆ˜๊ฐ€ ์•„๋‹ˆ๋ผ ํ‘œ๋ณธยท์ด์ƒ์น˜ยท๊ณ ์› ํœด๋ฆฌ์Šคํ‹ฑ์ž…๋‹ˆ๋‹ค. ์ ์šฉ ๊ฐ€๋Šฅ๋„%=100โˆ’๊ณผ์ ํ•ฉ์œ„ํ—˜%. DB ์ ์šฉ ๋ฒ„ํŠผ ํ™œ์„ฑ ์กฐ๊ฑด(gated PnL>0)๊ณผ๋Š” ๋ณ„๊ฐœ์ž…๋‹ˆ๋‹ค._ + +## ์ตœ์ข… ์„ ํƒ ํ›„๋ณด (๊ทœ์น™ ยท DB ์ ์šฉ ์ „ ํ™•์ธ) +- ์•„๋ž˜๋Š” **์—ญํ• ์ด ๋‹ค๋ฅธ** 4์ข… ํ›„๋ณด์ž…๋‹ˆ๋‹ค. mode Top10 1์œ„ โ‰  ์ต์ ˆ ๋Œ€ํ‘œ ยท **DB 1์ˆœ์œ„๋Š” ์‚ฌํ›„ํ•ฉ๊ฒฉ(gated)** ์ž…๋‹ˆ๋‹ค. +- mode pool: `positive` ยท scoring: `band_proximity_p25_p75` + +### ํ›„๋ณด 4์ข… +- **โ‘  ์‚ฌํ›„ํ•ฉ๊ฒฉ 1์œ„ (apply: gated)**: ์—†์Œ +- **โ‘ก ์•ˆ์ • 1์œ„ (apply: stable)**: ์—†์Œ +- **โ‘ข mode_combo (apply: mode)**: ์—†์Œ (๋ฏธ์‚ฐ์ถœยท๊ตฌ JSON) +- **โ‘ฃ mode Top10 1์œ„ (apply: consensus ยท ๋ฐด๋“œ ์ „ํ˜• trial)**: ์—†์Œ +- mode Top10 meta: pool 0๊ฑด ยท ์ถ• 0๊ฐœ + +### ์ถ”์ฒœ (์ž๋™ ยท confirm ํ•„์ˆ˜) +1. **์‚ฌํ›„ํ•ฉ๊ฒฉ 0๊ฑด โ†’ DB ์ ์šฉ ๋น„๊ถŒ์žฅ.** ํ˜„ํ–‰ DB ์œ ์ง€ + ์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑยท๊ธฐ๊ฐ„ ์žฌ๊ฒ€์ฆ. +- โš  ์•ˆ์ • ๊ฒŒ์ดํŠธ 0๊ฑด โ†’ ์•ˆ์ • Top์€ **์ ์ˆ˜์ˆœ ํด๋ฐฑ** (์•ˆ์ • ๊ฒŒ์ดํŠธ 0๊ฑด โ†’ ํ•™์Šตํ’€ ์•ˆ์ •์ ์ˆ˜์ˆœ TopN (๋งˆ์ด๋„ˆ์Šค PnL ํฌํ•จ ยท ์ƒ๋Œ€๋น„๊ต)) + +## ์ด์ „ ์žฅ์—์„œ๋Š” +- ์‹ค๋งค ๋™๊ธฐ๊ฐ„ ์ฒญ์‚ฐ 25๊ฑด ยท ์Šน๋ฅ  24% ยท ํ•ฉ์‚ฐ PnL -87,351์› (๋ฐฑํ…Œ Optuna์™€ ์ˆซ์ž ๋‹ฌ๋ผ๋„ ์ •์ƒ โ€” ๊ณ ์ŠคํŠธยท์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑ ๊ฒฝ๋กœ ์ฐจ์ด). +- ์ด ๊ธฐ๊ฐ„ ๋ฐฑํ…Œ์—์„œ๋Š” **์œ ์˜๋ฏธํ•œ ํ†ต๊ณผ ์กฐํ•ฉ์ด ๊ฑฐ์˜ ์—†์—ˆ์Šต๋‹ˆ๋‹ค.** ์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑยท์†์ ˆยท์‹œ๊ฐ„์ฐฝ์„ ๋จผ์ € ์ ๊ฒ€ํ•˜์„ธ์š” (๋ŒํŒŒ 0๊ฑด์ด๋ฉด ํŠนํžˆ). + +## ์•ž์œผ๋กœ ์žฅ์—์„œ๋Š” +- **1~2์ผ Optuna best๋ฅผ ๋ฐ”๋กœ ์‹ค๋งค์— ๋„ฃ์ง€ ๋งˆ์„ธ์š”.** ๋‹ค์ผ(โ‰ฅ5๊ฑฐ๋ž˜์ผ) ์žฌ๊ฒ€์ฆยท์›น๋ฐฑํ…Œ 1ํšŒ ํ›„ ๊ฒ€ํ† . +- ์ ์šฉ ์‹œ์—๋Š” `results_gated` ํ›„๋ณด๋งŒ. ํƒ์ƒ‰์šฉ best(objective)์™€ ๋‹ค๋ฅผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. +- ์žฅ์ด ์ข์•„์ง€๊ฑฐ๋‚˜ ๋ณ€๋™์„ฑ์ด ์ปค์ง€๋ฉด: ์†์ ˆยทํŠธ๋ ˆ์ผยท์‹œ๊ฐ„์ฐฝ์ด ๋จผ์ € ๊นจ์ง‘๋‹ˆ๋‹ค. ์Šน๋ฅ  ์ž๋ž‘๋ณด๋‹ค **์†์ ˆ์ด ์‚ด์•„ ์žˆ๋Š”์ง€**๋ฅผ ๋ณด์„ธ์š”. +- ํ˜„์žฌ ์‚ฌํ›„ํ•ฉ๊ฒฉ 0๊ฑด โ†’ ํŒŒ๋ผ๋ฏธํ„ฐ ์œ ์ง€(ํ˜„ํ–‰ DB) + ์œ ๋‹ˆ๋ฒ„์Šค/๋ฐ์ดํ„ฐ ์ ๊ฒ€์ด ์šฐ์„ ์ž…๋‹ˆ๋‹ค. + +_์ƒ์„ฑ: 2026-09-04 13:33:01 (rule)_ + +## AI ์ฝ”๋ฉ˜ํŠธ (์ด์ „ ์žฅ / ์•ž์œผ๋กœ ์žฅ) [gemini] + +**์ด์ „ ์žฅ์—์„œ๋Š”:** +5๊ฑฐ๋ž˜์ผ ๋ฐฑํ…Œ์ŠคํŠธ์—์„œ `min_trades=10` ๊ธฐ์ค€์„ ์ถฉ์กฑํ•œ ํ†ต๊ณผ ์กฐํ•ฉ์€ ์ „๋ฌดํ•ฉ๋‹ˆ๋‹ค. `WRโ‰ฅ40% PFโ‰ฅ1` ํ›„๋ณด๋„ ์—†์–ด '์ ์šฉ ๋ถˆ๊ฐ€' ์ƒํƒœ์ž…๋‹ˆ๋‹ค. ์ด๋Š” ํ‘œ๋ณธ ๋ถ€์กฑ, ํ˜„ ์ „๋žต ๊ธฐ๊ฐ„ ๋ถ€์ ํ•ฉ ๋˜๋Š” ๊ณผ์ ํ•ฉ ์œ„ํ—˜์„ ๋‚˜ํƒ€๋‚ด๋ฉฐ, ์‹ค๋งค์™€ ๋ฐฑํ…Œ ๊ฐ„ '๊ณ ์ŠคํŠธ ํผ์ง€' ๊ฐ™์€ ๊ดด๋ฆฌ ๋ฐœ์ƒ์„ ๊ฒฝ๊ณ ํ•ฉ๋‹ˆ๋‹ค. + +**์•ž์œผ๋กœ ์žฅ์—์„œ๋Š”:** +์‚ฌํ›„ํ•ฉ๊ฒฉ ์กฐํ•ฉ์ด ์—†์œผ๋ฏ€๋กœ ํ˜„ํ–‰ DB ์œ ์ง€, ์œ ๋‹ˆ๋ฒ„์Šค/ํ‹ฑ/๊ธฐ๊ฐ„ ์žฌ๊ฒ€์ฆ์ด ์ตœ์šฐ์„ ์ž…๋‹ˆ๋‹ค. 5์ผ ๊ฒฐ๊ณผ๋งŒ์œผ๋กœ `mode Top10 1์œ„`๋ฅผ ์ต์ ˆ ๋Œ€ํ‘œ๋กœ ๋‹จ์ •ํ•˜๊ฑฐ๋‚˜ ๋ฐ”๋กœ ์‹ค๋งค ์ ์šฉ์€ ๊ธˆ๋ฌผ์ž…๋‹ˆ๋‹ค. ๊ณผ์ ํ•ฉยทํ‘œ๋ณธ ๋ถ€์กฑ ์œ„ํ—˜์ด ํฌ๋‹ˆ, ๋‹ค์ผ ์žฌ๊ฒ€์ฆ ์—†์ด ํ™•์ • ์ˆ˜์ต ์•ฝ์†์ด๋‚˜ ํŠน์ • ์ข…๋ชฉ ์ถ”์ฒœ์€ ์ ˆ๋Œ€ ์‚ผ๊ฐ€์„ธ์š”. diff --git a/kis_trader/backtest/results/optuna_breakout_tpe_20260904_134219.briefing.md b/kis_trader/backtest/results/optuna_breakout_tpe_20260904_134219.briefing.md new file mode 100644 index 0000000..8fa8228 --- /dev/null +++ b/kis_trader/backtest/results/optuna_breakout_tpe_20260904_134219.briefing.md @@ -0,0 +1,49 @@ +# Optuna ๋ธŒ๋ฆฌํ•‘ โ€” ๋ŒํŒŒ (tpe) +๊ธฐ๊ฐ„: 2026-08-31 ~ 2026-09-04 (๊ฑฐ๋ž˜์ผโ‰ˆ5์ผ) ยท trials 200/200 +ํƒ์ƒ‰ ๊ฒŒ์ดํŠธ: WRโ‰ฅ0% PFโ‰ฅ0 ยท min_tradesโ‰ฅ10 | ํ›„๋ณด ๊ฒŒ์ดํŠธ: WRโ‰ฅ40% PFโ‰ฅ1 ยท min_tradesโ‰ฅ10 +- min_trades=10: **ํ•ฉ๊ฒฉ ์ธ์ • ์ตœ์†Œ ๊ฑฐ๋ž˜ ๊ฑด์ˆ˜**(ํ‘œ๋ณธ ๋ถ€์กฑยท์šฐ์—ฐ ์Šน๋ฅ  ๋ฐฉ์ง€). ์ด๋ณด๋‹ค ์ ์€ ์กฐํ•ฉ์€ ํ•™์Šต/ํ›„๋ณด ์ง‘๊ณ„์—์„œ ์ œ์™ธ๋ฉ๋‹ˆ๋‹ค. +ํ•™์Šต์šฉ ํ†ต๊ณผ 0๊ฑด ยท ์‚ฌํ›„ํ•ฉ๊ฒฉ(results_gated) 0๊ฑด + +## ๊ณผ์ ํ•ฉยท์ ์šฉ ๊ฐ€๋Šฅ๋„ (ํœด๋ฆฌ์Šคํ‹ฑ) +- **๊ณผ์ ํ•ฉ ์œ„ํ—˜ 33.0%** ยท **์ ์šฉ ๊ฐ€๋Šฅ๋„ 67.0%** ยท ํŒ์ •: **์ƒ๋Œ€์ ์œผ๋กœ๋‚ฎ์Œ** โ€” ํœด๋ฆฌ์Šคํ‹ฑ์ƒ ์œ„ํ—˜ ์ƒ๋Œ€์  ๋‚ฎ์Œ โ€” ๊ทธ๋ž˜๋„ ๋‹ค์ผ ํ™•์ธ ๊ถŒ์žฅ + - ํ‘œ๋ณธ ์žฅ์ผ: +0.0p โ€” ๊ฑฐ๋ž˜์ผโ‰ˆ5์ผ โ€” ํ‘œ๋ณธ ์ผ์ˆ˜ ์ƒ๋Œ€์  ์–‘ํ˜ธ + - ๊ฑฐ๋ž˜ ํ‘œ๋ณธ: +25.0p โ€” ํ†ต๊ณผ ํ›„๋ณด ์—†์Œ โ€” ์ ์šฉ ๋ถˆ๊ฐ€ + - ์Šน๋ฅ ยทPF ์ด์ƒ์น˜: +0.0p โ€” ์ด์ƒ์น˜ ์—†์Œ + - ๊ฒŒ์ดํŠธ ์ปค๋ฒ„: +8.0p โ€” ํ•™์Šตยทgated ๋ชจ๋‘ ๋น„์–ด ์žˆ์Œ + - PnL ๊ณ ์›: +0.0p โ€” ๊ณ ์› ํŒ์ • ์Šคํ‚ต +- _์ฐธ๊ณ : ๊ณผ์ ํ•ฉ%๋Š” ๊ต์ฐจ๊ฒ€์ฆ ์ ์ˆ˜๊ฐ€ ์•„๋‹ˆ๋ผ ํ‘œ๋ณธยท์ด์ƒ์น˜ยท๊ณ ์› ํœด๋ฆฌ์Šคํ‹ฑ์ž…๋‹ˆ๋‹ค. ์ ์šฉ ๊ฐ€๋Šฅ๋„%=100โˆ’๊ณผ์ ํ•ฉ์œ„ํ—˜%. DB ์ ์šฉ ๋ฒ„ํŠผ ํ™œ์„ฑ ์กฐ๊ฑด(gated PnL>0)๊ณผ๋Š” ๋ณ„๊ฐœ์ž…๋‹ˆ๋‹ค._ + +## ์ตœ์ข… ์„ ํƒ ํ›„๋ณด (๊ทœ์น™ ยท DB ์ ์šฉ ์ „ ํ™•์ธ) +- ์•„๋ž˜๋Š” **์—ญํ• ์ด ๋‹ค๋ฅธ** 4์ข… ํ›„๋ณด์ž…๋‹ˆ๋‹ค. mode Top10 1์œ„ โ‰  ์ต์ ˆ ๋Œ€ํ‘œ ยท **DB 1์ˆœ์œ„๋Š” ์‚ฌํ›„ํ•ฉ๊ฒฉ(gated)** ์ž…๋‹ˆ๋‹ค. +- mode pool: `positive` ยท scoring: `band_proximity_p25_p75` + +### ํ›„๋ณด 4์ข… +- **โ‘  ์‚ฌํ›„ํ•ฉ๊ฒฉ 1์œ„ (apply: gated)**: ์—†์Œ +- **โ‘ก ์•ˆ์ • 1์œ„ (apply: stable)**: ์—†์Œ +- **โ‘ข mode_combo (apply: mode)**: ์—†์Œ (๋ฏธ์‚ฐ์ถœยท๊ตฌ JSON) +- **โ‘ฃ mode Top10 1์œ„ (apply: consensus ยท ๋ฐด๋“œ ์ „ํ˜• trial)**: ์—†์Œ +- mode Top10 meta: pool 0๊ฑด ยท ์ถ• 0๊ฐœ + +### ์ถ”์ฒœ (์ž๋™ ยท confirm ํ•„์ˆ˜) +1. **์‚ฌํ›„ํ•ฉ๊ฒฉ 0๊ฑด โ†’ DB ์ ์šฉ ๋น„๊ถŒ์žฅ.** ํ˜„ํ–‰ DB ์œ ์ง€ + ์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑยท๊ธฐ๊ฐ„ ์žฌ๊ฒ€์ฆ. +- โš  ์•ˆ์ • ๊ฒŒ์ดํŠธ 0๊ฑด โ†’ ์•ˆ์ • Top์€ **์ ์ˆ˜์ˆœ ํด๋ฐฑ** (์•ˆ์ • ๊ฒŒ์ดํŠธ 0๊ฑด โ†’ ํ•™์Šตํ’€ ์•ˆ์ •์ ์ˆ˜์ˆœ TopN (๋งˆ์ด๋„ˆ์Šค PnL ํฌํ•จ ยท ์ƒ๋Œ€๋น„๊ต)) + +## ์ด์ „ ์žฅ์—์„œ๋Š” +- ์‹ค๋งค ๋™๊ธฐ๊ฐ„ ์ฒญ์‚ฐ 25๊ฑด ยท ์Šน๋ฅ  24% ยท ํ•ฉ์‚ฐ PnL -87,351์› (๋ฐฑํ…Œ Optuna์™€ ์ˆซ์ž ๋‹ฌ๋ผ๋„ ์ •์ƒ โ€” ๊ณ ์ŠคํŠธยท์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑ ๊ฒฝ๋กœ ์ฐจ์ด). +- ์ด ๊ธฐ๊ฐ„ ๋ฐฑํ…Œ์—์„œ๋Š” **์œ ์˜๋ฏธํ•œ ํ†ต๊ณผ ์กฐํ•ฉ์ด ๊ฑฐ์˜ ์—†์—ˆ์Šต๋‹ˆ๋‹ค.** ์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑยท์†์ ˆยท์‹œ๊ฐ„์ฐฝ์„ ๋จผ์ € ์ ๊ฒ€ํ•˜์„ธ์š” (๋ŒํŒŒ 0๊ฑด์ด๋ฉด ํŠนํžˆ). + +## ์•ž์œผ๋กœ ์žฅ์—์„œ๋Š” +- **1~2์ผ Optuna best๋ฅผ ๋ฐ”๋กœ ์‹ค๋งค์— ๋„ฃ์ง€ ๋งˆ์„ธ์š”.** ๋‹ค์ผ(โ‰ฅ5๊ฑฐ๋ž˜์ผ) ์žฌ๊ฒ€์ฆยท์›น๋ฐฑํ…Œ 1ํšŒ ํ›„ ๊ฒ€ํ† . +- ์ ์šฉ ์‹œ์—๋Š” `results_gated` ํ›„๋ณด๋งŒ. ํƒ์ƒ‰์šฉ best(objective)์™€ ๋‹ค๋ฅผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. +- ์žฅ์ด ์ข์•„์ง€๊ฑฐ๋‚˜ ๋ณ€๋™์„ฑ์ด ์ปค์ง€๋ฉด: ์†์ ˆยทํŠธ๋ ˆ์ผยท์‹œ๊ฐ„์ฐฝ์ด ๋จผ์ € ๊นจ์ง‘๋‹ˆ๋‹ค. ์Šน๋ฅ  ์ž๋ž‘๋ณด๋‹ค **์†์ ˆ์ด ์‚ด์•„ ์žˆ๋Š”์ง€**๋ฅผ ๋ณด์„ธ์š”. +- ํ˜„์žฌ ์‚ฌํ›„ํ•ฉ๊ฒฉ 0๊ฑด โ†’ ํŒŒ๋ผ๋ฏธํ„ฐ ์œ ์ง€(ํ˜„ํ–‰ DB) + ์œ ๋‹ˆ๋ฒ„์Šค/๋ฐ์ดํ„ฐ ์ ๊ฒ€์ด ์šฐ์„ ์ž…๋‹ˆ๋‹ค. + +_์ƒ์„ฑ: 2026-09-04 13:42:19 (rule)_ + +## AI ์ฝ”๋ฉ˜ํŠธ (์ด์ „ ์žฅ / ์•ž์œผ๋กœ ์žฅ) [gemini] + +**์ด์ „ ์žฅ์—์„œ๋Š”** +5์ผ๊ฐ„์˜ ์งง์€ ๋ฐฑํ…Œ์ŠคํŠธ์—์„œ ์œ ์˜๋ฏธํ•œ ์ „๋žต ์กฐํ•ฉ์ด ์ „๋ฌดํ–ˆ์Šต๋‹ˆ๋‹ค. ์‹ค๋งค๋Š” -8.7๋งŒ์› ์†์‹ค๋กœ ๋ฐฑํ…Œ ๊ฒฐ๊ณผ์™€ ํฐ ๊ดด๋ฆฌ๋ฅผ ๋ณด์ž…๋‹ˆ๋‹ค. ์ด๋Š” ๊ธฐ๊ฐ„/์œ ๋‹ˆ๋ฒ„์Šค/๋ฐ์ดํ„ฐ ๋“ฑ ๊ทผ๋ณธ์  ์žฌ๊ฒ€ํ† ๊ฐ€ ์‹œ๊ธ‰ํ•˜๋ฉฐ, ๊ณผ์ ํ•ฉ๊ณผ ํ‘œ๋ณธ ๋ถ€์กฑ ์œ„ํ—˜์ด ๋งค์šฐ ๋†’์Œ์„ ๊ฒฝ๊ณ ํ•ฉ๋‹ˆ๋‹ค. + +**์•ž์œผ๋กœ ์žฅ์—์„œ๋Š”** +์ด ์งง์€ ๋ฐฑํ…Œ์ŠคํŠธ ๊ฒฐ๊ณผ๋ฅผ ์ ˆ๋Œ€ ๋ฐ”๋กœ ์‹ค๋งค์— ์ ์šฉํ•ด์„  ์•ˆ ๋ฉ๋‹ˆ๋‹ค. ๊ณผ์ ํ•ฉ/ํ‘œ๋ณธ ๋ถ€์กฑ ์œ„ํ—˜์ด ํฌ๊ณ , ์‹ค๋งค๋Š” ๋ฐฑํ…Œ์ŠคํŠธ์™€ ๊ดด๋ฆฌ๋ฉ๋‹ˆ๋‹ค. `mode Top10 1์œ„`๋ฅผ ์ต์ ˆ ๋Œ€ํ‘œ๋กœ ๋‹จ์ •ํ•˜์ง€ ๋งˆ์„ธ์š”. `์‚ฌํ›„ํ•ฉ๊ฒฉ` ํ›„๋ณด 0๊ฑด์ด๋ฏ€๋กœ ํ˜„ํ–‰ DB๋ฅผ ์œ ์ง€ํ•˜๋ฉฐ, ์œ ๋‹ˆ๋ฒ„์Šค/๋ฐ์ดํ„ฐ ์žฌ์ ๊ฒ€ ๋ฐ ์†์ ˆ ๊ธฐ์ค€ ์ค€์ˆ˜๊ฐ€ ์šฐ์„ ์ž…๋‹ˆ๋‹ค. diff --git a/kis_trader/backtest/results/optuna_breakout_tpe_20260904_135117.briefing.md b/kis_trader/backtest/results/optuna_breakout_tpe_20260904_135117.briefing.md new file mode 100644 index 0000000..e0510b3 --- /dev/null +++ b/kis_trader/backtest/results/optuna_breakout_tpe_20260904_135117.briefing.md @@ -0,0 +1,49 @@ +# Optuna ๋ธŒ๋ฆฌํ•‘ โ€” ๋ŒํŒŒ (tpe) +๊ธฐ๊ฐ„: 2026-08-31 ~ 2026-09-04 (๊ฑฐ๋ž˜์ผโ‰ˆ5์ผ) ยท trials 200/200 +ํƒ์ƒ‰ ๊ฒŒ์ดํŠธ: WRโ‰ฅ0% PFโ‰ฅ0 ยท min_tradesโ‰ฅ10 | ํ›„๋ณด ๊ฒŒ์ดํŠธ: WRโ‰ฅ40% PFโ‰ฅ1 ยท min_tradesโ‰ฅ10 +- min_trades=10: **ํ•ฉ๊ฒฉ ์ธ์ • ์ตœ์†Œ ๊ฑฐ๋ž˜ ๊ฑด์ˆ˜**(ํ‘œ๋ณธ ๋ถ€์กฑยท์šฐ์—ฐ ์Šน๋ฅ  ๋ฐฉ์ง€). ์ด๋ณด๋‹ค ์ ์€ ์กฐํ•ฉ์€ ํ•™์Šต/ํ›„๋ณด ์ง‘๊ณ„์—์„œ ์ œ์™ธ๋ฉ๋‹ˆ๋‹ค. +ํ•™์Šต์šฉ ํ†ต๊ณผ 0๊ฑด ยท ์‚ฌํ›„ํ•ฉ๊ฒฉ(results_gated) 0๊ฑด + +## ๊ณผ์ ํ•ฉยท์ ์šฉ ๊ฐ€๋Šฅ๋„ (ํœด๋ฆฌ์Šคํ‹ฑ) +- **๊ณผ์ ํ•ฉ ์œ„ํ—˜ 33.0%** ยท **์ ์šฉ ๊ฐ€๋Šฅ๋„ 67.0%** ยท ํŒ์ •: **์ƒ๋Œ€์ ์œผ๋กœ๋‚ฎ์Œ** โ€” ํœด๋ฆฌ์Šคํ‹ฑ์ƒ ์œ„ํ—˜ ์ƒ๋Œ€์  ๋‚ฎ์Œ โ€” ๊ทธ๋ž˜๋„ ๋‹ค์ผ ํ™•์ธ ๊ถŒ์žฅ + - ํ‘œ๋ณธ ์žฅ์ผ: +0.0p โ€” ๊ฑฐ๋ž˜์ผโ‰ˆ5์ผ โ€” ํ‘œ๋ณธ ์ผ์ˆ˜ ์ƒ๋Œ€์  ์–‘ํ˜ธ + - ๊ฑฐ๋ž˜ ํ‘œ๋ณธ: +25.0p โ€” ํ†ต๊ณผ ํ›„๋ณด ์—†์Œ โ€” ์ ์šฉ ๋ถˆ๊ฐ€ + - ์Šน๋ฅ ยทPF ์ด์ƒ์น˜: +0.0p โ€” ์ด์ƒ์น˜ ์—†์Œ + - ๊ฒŒ์ดํŠธ ์ปค๋ฒ„: +8.0p โ€” ํ•™์Šตยทgated ๋ชจ๋‘ ๋น„์–ด ์žˆ์Œ + - PnL ๊ณ ์›: +0.0p โ€” ๊ณ ์› ํŒ์ • ์Šคํ‚ต +- _์ฐธ๊ณ : ๊ณผ์ ํ•ฉ%๋Š” ๊ต์ฐจ๊ฒ€์ฆ ์ ์ˆ˜๊ฐ€ ์•„๋‹ˆ๋ผ ํ‘œ๋ณธยท์ด์ƒ์น˜ยท๊ณ ์› ํœด๋ฆฌ์Šคํ‹ฑ์ž…๋‹ˆ๋‹ค. ์ ์šฉ ๊ฐ€๋Šฅ๋„%=100โˆ’๊ณผ์ ํ•ฉ์œ„ํ—˜%. DB ์ ์šฉ ๋ฒ„ํŠผ ํ™œ์„ฑ ์กฐ๊ฑด(gated PnL>0)๊ณผ๋Š” ๋ณ„๊ฐœ์ž…๋‹ˆ๋‹ค._ + +## ์ตœ์ข… ์„ ํƒ ํ›„๋ณด (๊ทœ์น™ ยท DB ์ ์šฉ ์ „ ํ™•์ธ) +- ์•„๋ž˜๋Š” **์—ญํ• ์ด ๋‹ค๋ฅธ** 4์ข… ํ›„๋ณด์ž…๋‹ˆ๋‹ค. mode Top10 1์œ„ โ‰  ์ต์ ˆ ๋Œ€ํ‘œ ยท **DB 1์ˆœ์œ„๋Š” ์‚ฌํ›„ํ•ฉ๊ฒฉ(gated)** ์ž…๋‹ˆ๋‹ค. +- mode pool: `positive` ยท scoring: `band_proximity_p25_p75` + +### ํ›„๋ณด 4์ข… +- **โ‘  ์‚ฌํ›„ํ•ฉ๊ฒฉ 1์œ„ (apply: gated)**: ์—†์Œ +- **โ‘ก ์•ˆ์ • 1์œ„ (apply: stable)**: ์—†์Œ +- **โ‘ข mode_combo (apply: mode)**: ์—†์Œ (๋ฏธ์‚ฐ์ถœยท๊ตฌ JSON) +- **โ‘ฃ mode Top10 1์œ„ (apply: consensus ยท ๋ฐด๋“œ ์ „ํ˜• trial)**: ์—†์Œ +- mode Top10 meta: pool 0๊ฑด ยท ์ถ• 0๊ฐœ + +### ์ถ”์ฒœ (์ž๋™ ยท confirm ํ•„์ˆ˜) +1. **์‚ฌํ›„ํ•ฉ๊ฒฉ 0๊ฑด โ†’ DB ์ ์šฉ ๋น„๊ถŒ์žฅ.** ํ˜„ํ–‰ DB ์œ ์ง€ + ์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑยท๊ธฐ๊ฐ„ ์žฌ๊ฒ€์ฆ. +- โš  ์•ˆ์ • ๊ฒŒ์ดํŠธ 0๊ฑด โ†’ ์•ˆ์ • Top์€ **์ ์ˆ˜์ˆœ ํด๋ฐฑ** (์•ˆ์ • ๊ฒŒ์ดํŠธ 0๊ฑด โ†’ ํ•™์Šตํ’€ ์•ˆ์ •์ ์ˆ˜์ˆœ TopN (๋งˆ์ด๋„ˆ์Šค PnL ํฌํ•จ ยท ์ƒ๋Œ€๋น„๊ต)) + +## ์ด์ „ ์žฅ์—์„œ๋Š” +- ์‹ค๋งค ๋™๊ธฐ๊ฐ„ ์ฒญ์‚ฐ 25๊ฑด ยท ์Šน๋ฅ  24% ยท ํ•ฉ์‚ฐ PnL -87,351์› (๋ฐฑํ…Œ Optuna์™€ ์ˆซ์ž ๋‹ฌ๋ผ๋„ ์ •์ƒ โ€” ๊ณ ์ŠคํŠธยท์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑ ๊ฒฝ๋กœ ์ฐจ์ด). +- ์ด ๊ธฐ๊ฐ„ ๋ฐฑํ…Œ์—์„œ๋Š” **์œ ์˜๋ฏธํ•œ ํ†ต๊ณผ ์กฐํ•ฉ์ด ๊ฑฐ์˜ ์—†์—ˆ์Šต๋‹ˆ๋‹ค.** ์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑยท์†์ ˆยท์‹œ๊ฐ„์ฐฝ์„ ๋จผ์ € ์ ๊ฒ€ํ•˜์„ธ์š” (๋ŒํŒŒ 0๊ฑด์ด๋ฉด ํŠนํžˆ). + +## ์•ž์œผ๋กœ ์žฅ์—์„œ๋Š” +- **1~2์ผ Optuna best๋ฅผ ๋ฐ”๋กœ ์‹ค๋งค์— ๋„ฃ์ง€ ๋งˆ์„ธ์š”.** ๋‹ค์ผ(โ‰ฅ5๊ฑฐ๋ž˜์ผ) ์žฌ๊ฒ€์ฆยท์›น๋ฐฑํ…Œ 1ํšŒ ํ›„ ๊ฒ€ํ† . +- ์ ์šฉ ์‹œ์—๋Š” `results_gated` ํ›„๋ณด๋งŒ. ํƒ์ƒ‰์šฉ best(objective)์™€ ๋‹ค๋ฅผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. +- ์žฅ์ด ์ข์•„์ง€๊ฑฐ๋‚˜ ๋ณ€๋™์„ฑ์ด ์ปค์ง€๋ฉด: ์†์ ˆยทํŠธ๋ ˆ์ผยท์‹œ๊ฐ„์ฐฝ์ด ๋จผ์ € ๊นจ์ง‘๋‹ˆ๋‹ค. ์Šน๋ฅ  ์ž๋ž‘๋ณด๋‹ค **์†์ ˆ์ด ์‚ด์•„ ์žˆ๋Š”์ง€**๋ฅผ ๋ณด์„ธ์š”. +- ํ˜„์žฌ ์‚ฌํ›„ํ•ฉ๊ฒฉ 0๊ฑด โ†’ ํŒŒ๋ผ๋ฏธํ„ฐ ์œ ์ง€(ํ˜„ํ–‰ DB) + ์œ ๋‹ˆ๋ฒ„์Šค/๋ฐ์ดํ„ฐ ์ ๊ฒ€์ด ์šฐ์„ ์ž…๋‹ˆ๋‹ค. + +_์ƒ์„ฑ: 2026-09-04 13:51:17 (rule)_ + +## AI ์ฝ”๋ฉ˜ํŠธ (์ด์ „ ์žฅ / ์•ž์œผ๋กœ ์žฅ) [gemini] + +**์ด์ „ ์žฅ์—์„œ๋Š”** +์ง€๋‚œ 5๊ฑฐ๋ž˜์ผ๊ฐ„ Optuna ํƒ์ƒ‰ ๊ฒฐ๊ณผ, ์ตœ์†Œ ๊ฑฐ๋ž˜ ๊ฑด์ˆ˜(10๊ฑด) ๊ธฐ์ค€์„ ํ†ต๊ณผํ•œ ์œ ์˜๋ฏธํ•œ ์ „๋žต์€ ์—†์—ˆ์Šต๋‹ˆ๋‹ค. ๋™๊ธฐ๊ฐ„ ์‹ค๋งค๋Š” PnL -8๋งŒ์›๋Œ€๋กœ ๋ฐฑํ…Œ์™€ ์‹ค์ œ ๋งค๋งค ๊ฐ„ ๊ดด๋ฆฌ(๊ณ ์ŠคํŠธ ํ˜„์ƒ, ์œ ๋‹ˆ๋ฒ„์Šค/ํ‹ฑ ์ฐจ์ด)๊ฐ€ ์ปธ์Šต๋‹ˆ๋‹ค. ์ด๋Š” ํ‘œ๋ณธ ๋ถ€์กฑ ๋ฐ ์šฐ์—ฐํ•œ ์Šน๋ฅ  ๋ฐฉ์ง€๋ฅผ ์œ„ํ•จ์ด์—ˆ์Šต๋‹ˆ๋‹ค. + +**์•ž์œผ๋กœ ์žฅ์—์„œ๋Š”** +ํ˜„์žฌ ์‚ฌํ›„ํ•ฉ๊ฒฉ(gated) ํ›„๋ณด 0๊ฑด์œผ๋กœ ์–ด๋–ค Optuna ๊ฒฐ๊ณผ๋„ ์‹ค๋งค ์ ์šฉ์€ ๊ธˆ์ง€ํ•ฉ๋‹ˆ๋‹ค. ๋‹จ๊ธฐ ๋ฐฑํ…Œ๋Š” ๊ณผ์ ํ•ฉ, ํ‘œ๋ณธ ๋ถ€์กฑ ์œ„ํ—˜์ด ํฌ๊ณ , ์‹ค๋งคโ†”๋ฐฑํ…Œ ๊ดด๋ฆฌ๋„ ํฝ๋‹ˆ๋‹ค. 'mode Top10 1์œ„'๋Š” ์ต์ ˆ ๋Œ€ํ‘œ๊ฐ€ ์•„๋‹ˆ๋ฉฐ, ์ ์šฉ์€ ์˜ค์ง ์‚ฌํ›„ํ•ฉ๊ฒฉ ํ›„๋ณด๋งŒ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค. ๋‹ค์ผ ์žฌ๊ฒ€์ฆ ๋ฐ ์›น๋ฐฑํ…Œ๊ฐ€ ํ•„์ˆ˜์ด๋ฉฐ, ํŒŒ๋ผ๋ฏธํ„ฐ ์œ ์ง€์™€ ์œ ๋‹ˆ๋ฒ„์Šค/๋ฐ์ดํ„ฐ ์ ๊ฒ€์„ ์šฐ์„ ํ•ฉ๋‹ˆ๋‹ค. ์‹œ์žฅ ๋ณ€๋™ ์‹œ ์Šน๋ฅ ๋ณด๋‹ค ์†์ ˆ ์ž‘๋™ ์—ฌ๋ถ€๋ฅผ ํ™•์ธํ•˜์„ธ์š”. diff --git a/kis_trader/backtest/results/optuna_breakout_tpe_20260904_135717.briefing.md b/kis_trader/backtest/results/optuna_breakout_tpe_20260904_135717.briefing.md new file mode 100644 index 0000000..bbf7bb7 --- /dev/null +++ b/kis_trader/backtest/results/optuna_breakout_tpe_20260904_135717.briefing.md @@ -0,0 +1,49 @@ +# Optuna ๋ธŒ๋ฆฌํ•‘ โ€” ๋ŒํŒŒ (tpe) +๊ธฐ๊ฐ„: 2026-08-31 ~ 2026-09-04 (๊ฑฐ๋ž˜์ผโ‰ˆ5์ผ) ยท trials 200/200 +ํƒ์ƒ‰ ๊ฒŒ์ดํŠธ: WRโ‰ฅ0% PFโ‰ฅ0 ยท min_tradesโ‰ฅ10 | ํ›„๋ณด ๊ฒŒ์ดํŠธ: WRโ‰ฅ40% PFโ‰ฅ1 ยท min_tradesโ‰ฅ10 +- min_trades=10: **ํ•ฉ๊ฒฉ ์ธ์ • ์ตœ์†Œ ๊ฑฐ๋ž˜ ๊ฑด์ˆ˜**(ํ‘œ๋ณธ ๋ถ€์กฑยท์šฐ์—ฐ ์Šน๋ฅ  ๋ฐฉ์ง€). ์ด๋ณด๋‹ค ์ ์€ ์กฐํ•ฉ์€ ํ•™์Šต/ํ›„๋ณด ์ง‘๊ณ„์—์„œ ์ œ์™ธ๋ฉ๋‹ˆ๋‹ค. +ํ•™์Šต์šฉ ํ†ต๊ณผ 0๊ฑด ยท ์‚ฌํ›„ํ•ฉ๊ฒฉ(results_gated) 0๊ฑด + +## ๊ณผ์ ํ•ฉยท์ ์šฉ ๊ฐ€๋Šฅ๋„ (ํœด๋ฆฌ์Šคํ‹ฑ) +- **๊ณผ์ ํ•ฉ ์œ„ํ—˜ 33.0%** ยท **์ ์šฉ ๊ฐ€๋Šฅ๋„ 67.0%** ยท ํŒ์ •: **์ƒ๋Œ€์ ์œผ๋กœ๋‚ฎ์Œ** โ€” ํœด๋ฆฌ์Šคํ‹ฑ์ƒ ์œ„ํ—˜ ์ƒ๋Œ€์  ๋‚ฎ์Œ โ€” ๊ทธ๋ž˜๋„ ๋‹ค์ผ ํ™•์ธ ๊ถŒ์žฅ + - ํ‘œ๋ณธ ์žฅ์ผ: +0.0p โ€” ๊ฑฐ๋ž˜์ผโ‰ˆ5์ผ โ€” ํ‘œ๋ณธ ์ผ์ˆ˜ ์ƒ๋Œ€์  ์–‘ํ˜ธ + - ๊ฑฐ๋ž˜ ํ‘œ๋ณธ: +25.0p โ€” ํ†ต๊ณผ ํ›„๋ณด ์—†์Œ โ€” ์ ์šฉ ๋ถˆ๊ฐ€ + - ์Šน๋ฅ ยทPF ์ด์ƒ์น˜: +0.0p โ€” ์ด์ƒ์น˜ ์—†์Œ + - ๊ฒŒ์ดํŠธ ์ปค๋ฒ„: +8.0p โ€” ํ•™์Šตยทgated ๋ชจ๋‘ ๋น„์–ด ์žˆ์Œ + - PnL ๊ณ ์›: +0.0p โ€” ๊ณ ์› ํŒ์ • ์Šคํ‚ต +- _์ฐธ๊ณ : ๊ณผ์ ํ•ฉ%๋Š” ๊ต์ฐจ๊ฒ€์ฆ ์ ์ˆ˜๊ฐ€ ์•„๋‹ˆ๋ผ ํ‘œ๋ณธยท์ด์ƒ์น˜ยท๊ณ ์› ํœด๋ฆฌ์Šคํ‹ฑ์ž…๋‹ˆ๋‹ค. ์ ์šฉ ๊ฐ€๋Šฅ๋„%=100โˆ’๊ณผ์ ํ•ฉ์œ„ํ—˜%. DB ์ ์šฉ ๋ฒ„ํŠผ ํ™œ์„ฑ ์กฐ๊ฑด(gated PnL>0)๊ณผ๋Š” ๋ณ„๊ฐœ์ž…๋‹ˆ๋‹ค._ + +## ์ตœ์ข… ์„ ํƒ ํ›„๋ณด (๊ทœ์น™ ยท DB ์ ์šฉ ์ „ ํ™•์ธ) +- ์•„๋ž˜๋Š” **์—ญํ• ์ด ๋‹ค๋ฅธ** 4์ข… ํ›„๋ณด์ž…๋‹ˆ๋‹ค. mode Top10 1์œ„ โ‰  ์ต์ ˆ ๋Œ€ํ‘œ ยท **DB 1์ˆœ์œ„๋Š” ์‚ฌํ›„ํ•ฉ๊ฒฉ(gated)** ์ž…๋‹ˆ๋‹ค. +- mode pool: `positive` ยท scoring: `band_proximity_p25_p75` + +### ํ›„๋ณด 4์ข… +- **โ‘  ์‚ฌํ›„ํ•ฉ๊ฒฉ 1์œ„ (apply: gated)**: ์—†์Œ +- **โ‘ก ์•ˆ์ • 1์œ„ (apply: stable)**: ์—†์Œ +- **โ‘ข mode_combo (apply: mode)**: ์—†์Œ (๋ฏธ์‚ฐ์ถœยท๊ตฌ JSON) +- **โ‘ฃ mode Top10 1์œ„ (apply: consensus ยท ๋ฐด๋“œ ์ „ํ˜• trial)**: ์—†์Œ +- mode Top10 meta: pool 0๊ฑด ยท ์ถ• 0๊ฐœ + +### ์ถ”์ฒœ (์ž๋™ ยท confirm ํ•„์ˆ˜) +1. **์‚ฌํ›„ํ•ฉ๊ฒฉ 0๊ฑด โ†’ DB ์ ์šฉ ๋น„๊ถŒ์žฅ.** ํ˜„ํ–‰ DB ์œ ์ง€ + ์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑยท๊ธฐ๊ฐ„ ์žฌ๊ฒ€์ฆ. +- โš  ์•ˆ์ • ๊ฒŒ์ดํŠธ 0๊ฑด โ†’ ์•ˆ์ • Top์€ **์ ์ˆ˜์ˆœ ํด๋ฐฑ** (์•ˆ์ • ๊ฒŒ์ดํŠธ 0๊ฑด โ†’ ํ•™์Šตํ’€ ์•ˆ์ •์ ์ˆ˜์ˆœ TopN (๋งˆ์ด๋„ˆ์Šค PnL ํฌํ•จ ยท ์ƒ๋Œ€๋น„๊ต)) + +## ์ด์ „ ์žฅ์—์„œ๋Š” +- ์‹ค๋งค ๋™๊ธฐ๊ฐ„ ์ฒญ์‚ฐ 25๊ฑด ยท ์Šน๋ฅ  24% ยท ํ•ฉ์‚ฐ PnL -87,351์› (๋ฐฑํ…Œ Optuna์™€ ์ˆซ์ž ๋‹ฌ๋ผ๋„ ์ •์ƒ โ€” ๊ณ ์ŠคํŠธยท์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑ ๊ฒฝ๋กœ ์ฐจ์ด). +- ์ด ๊ธฐ๊ฐ„ ๋ฐฑํ…Œ์—์„œ๋Š” **์œ ์˜๋ฏธํ•œ ํ†ต๊ณผ ์กฐํ•ฉ์ด ๊ฑฐ์˜ ์—†์—ˆ์Šต๋‹ˆ๋‹ค.** ์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑยท์†์ ˆยท์‹œ๊ฐ„์ฐฝ์„ ๋จผ์ € ์ ๊ฒ€ํ•˜์„ธ์š” (๋ŒํŒŒ 0๊ฑด์ด๋ฉด ํŠนํžˆ). + +## ์•ž์œผ๋กœ ์žฅ์—์„œ๋Š” +- **1~2์ผ Optuna best๋ฅผ ๋ฐ”๋กœ ์‹ค๋งค์— ๋„ฃ์ง€ ๋งˆ์„ธ์š”.** ๋‹ค์ผ(โ‰ฅ5๊ฑฐ๋ž˜์ผ) ์žฌ๊ฒ€์ฆยท์›น๋ฐฑํ…Œ 1ํšŒ ํ›„ ๊ฒ€ํ† . +- ์ ์šฉ ์‹œ์—๋Š” `results_gated` ํ›„๋ณด๋งŒ. ํƒ์ƒ‰์šฉ best(objective)์™€ ๋‹ค๋ฅผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. +- ์žฅ์ด ์ข์•„์ง€๊ฑฐ๋‚˜ ๋ณ€๋™์„ฑ์ด ์ปค์ง€๋ฉด: ์†์ ˆยทํŠธ๋ ˆ์ผยท์‹œ๊ฐ„์ฐฝ์ด ๋จผ์ € ๊นจ์ง‘๋‹ˆ๋‹ค. ์Šน๋ฅ  ์ž๋ž‘๋ณด๋‹ค **์†์ ˆ์ด ์‚ด์•„ ์žˆ๋Š”์ง€**๋ฅผ ๋ณด์„ธ์š”. +- ํ˜„์žฌ ์‚ฌํ›„ํ•ฉ๊ฒฉ 0๊ฑด โ†’ ํŒŒ๋ผ๋ฏธํ„ฐ ์œ ์ง€(ํ˜„ํ–‰ DB) + ์œ ๋‹ˆ๋ฒ„์Šค/๋ฐ์ดํ„ฐ ์ ๊ฒ€์ด ์šฐ์„ ์ž…๋‹ˆ๋‹ค. + +_์ƒ์„ฑ: 2026-09-04 13:57:17 (rule)_ + +## AI ์ฝ”๋ฉ˜ํŠธ (์ด์ „ ์žฅ / ์•ž์œผ๋กœ ์žฅ) [gemini] + +**์ด์ „ ์žฅ์—์„œ๋Š”:** +์ตœ๊ทผ 5๊ฑฐ๋ž˜์ผ ๊ฐ„ ๋ฐฑํ…Œ์ŠคํŠธ์—์„œ ์œ ์˜๋ฏธํ•œ ์ „๋žต ์กฐํ•ฉ์ด ์ „ํ˜€ ๋ฐœ๊ฒฌ๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค(ํ•™์Šต/์‚ฌํ›„ํ•ฉ๊ฒฉ 0๊ฑด). ์‹ค์ œ ๋งค๋งค๋Š” 25๊ฑด, ์Šน๋ฅ  24%๋กœ ๋ฐฑํ…Œ ๊ฒฐ๊ณผ์™€ ์ฐจ์ด๊ฐ€ ์ปธ์Šต๋‹ˆ๋‹ค. ์ด๋Š” ๋ฐฑํ…Œ์ŠคํŠธ ํ™˜๊ฒฝ(๊ณ ์ŠคํŠธ/์œ ๋‹ˆ๋ฒ„์Šค/ํ‹ฑ)๊ณผ ์‹ค๋งค์˜ ๊ดด๋ฆฌ ๋•Œ๋ฌธ์ด๋ฉฐ, ํ‘œ๋ณธ ๋ถ€์กฑ ๋˜๋Š” ๊ณผ์ ํ•ฉ ์œ„ํ—˜ ์‹ ํ˜ธ์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์œ ๋‹ˆ๋ฒ„์Šค, ํ‹ฑ ๋ฐ์ดํ„ฐ, ์†์ ˆ ๊ธฐ์ค€์„ ๋ฉด๋ฐ€ํžˆ ์žฌ์ ๊ฒ€ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. + +**์•ž์œผ๋กœ ์žฅ์—์„œ๋Š”:** +Optuna ๊ฒฐ๊ณผ๋Š” ํƒ์ƒ‰์šฉ์ด๋ฉฐ, 1~2์ผ๊ฐ„์˜ ๋ฒ ์ŠคํŠธ ์กฐํ•ฉ์„ ๋ฐ”๋กœ ์‹ค๋งค์— ์ ์šฉํ•˜๋Š” ๊ฒƒ์€ ๋งค์šฐ ์œ„ํ—˜ํ•ฉ๋‹ˆ๋‹ค. ํŠนํžˆ '์‚ฌํ›„ํ•ฉ๊ฒฉ' ํ›„๋ณด๊ฐ€ ์—†๋Š” ์ง€๊ธˆ์€ ํ˜„ํ–‰ DB๋ฅผ ์œ ์ง€ํ•˜๋ฉฐ ๋ฐ์ดํ„ฐ ์ ๊ฒ€์ด ์ตœ์šฐ์„ ์ž…๋‹ˆ๋‹ค. `mode Top10 1์œ„`๋ฅผ ์ต์ ˆ ๋Œ€ํ‘œ๋กœ ๋‹จ์ •ํ•˜์ง€ ๋งˆ์‹ญ์‹œ์˜ค. ์‹ค์ œ ์ ์šฉ์€ '์‚ฌํ›„ํ•ฉ๊ฒฉ' ํ›„๋ณด๋งŒ ๊ฐ€๋Šฅํ•˜๋ฉฐ, ๊ณผ์ ํ•ฉ๊ณผ ๋ฐฑํ…Œ-์‹ค๋งค ๊ดด๋ฆฌ ๊ฐ€๋Šฅ์„ฑ์„ ๋Š˜ ๊ฒฝ๊ณ„ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ตœ์†Œ 5๊ฑฐ๋ž˜์ผ ์ด์ƒ ์žฌ๊ฒ€์ฆ ํ›„ ์‹ ์ค‘ํžˆ ์ ‘๊ทผํ•˜์„ธ์š”. diff --git a/kis_trader/backtest/results/optuna_breakout_tpe_20260904_140349.briefing.md b/kis_trader/backtest/results/optuna_breakout_tpe_20260904_140349.briefing.md new file mode 100644 index 0000000..08947b5 --- /dev/null +++ b/kis_trader/backtest/results/optuna_breakout_tpe_20260904_140349.briefing.md @@ -0,0 +1,49 @@ +# Optuna ๋ธŒ๋ฆฌํ•‘ โ€” ๋ŒํŒŒ (tpe) +๊ธฐ๊ฐ„: 2026-08-31 ~ 2026-09-04 (๊ฑฐ๋ž˜์ผโ‰ˆ5์ผ) ยท trials 200/200 +ํƒ์ƒ‰ ๊ฒŒ์ดํŠธ: WRโ‰ฅ0% PFโ‰ฅ0 ยท min_tradesโ‰ฅ10 | ํ›„๋ณด ๊ฒŒ์ดํŠธ: WRโ‰ฅ40% PFโ‰ฅ1 ยท min_tradesโ‰ฅ10 +- min_trades=10: **ํ•ฉ๊ฒฉ ์ธ์ • ์ตœ์†Œ ๊ฑฐ๋ž˜ ๊ฑด์ˆ˜**(ํ‘œ๋ณธ ๋ถ€์กฑยท์šฐ์—ฐ ์Šน๋ฅ  ๋ฐฉ์ง€). ์ด๋ณด๋‹ค ์ ์€ ์กฐํ•ฉ์€ ํ•™์Šต/ํ›„๋ณด ์ง‘๊ณ„์—์„œ ์ œ์™ธ๋ฉ๋‹ˆ๋‹ค. +ํ•™์Šต์šฉ ํ†ต๊ณผ 0๊ฑด ยท ์‚ฌํ›„ํ•ฉ๊ฒฉ(results_gated) 0๊ฑด + +## ๊ณผ์ ํ•ฉยท์ ์šฉ ๊ฐ€๋Šฅ๋„ (ํœด๋ฆฌ์Šคํ‹ฑ) +- **๊ณผ์ ํ•ฉ ์œ„ํ—˜ 33.0%** ยท **์ ์šฉ ๊ฐ€๋Šฅ๋„ 67.0%** ยท ํŒ์ •: **์ƒ๋Œ€์ ์œผ๋กœ๋‚ฎ์Œ** โ€” ํœด๋ฆฌ์Šคํ‹ฑ์ƒ ์œ„ํ—˜ ์ƒ๋Œ€์  ๋‚ฎ์Œ โ€” ๊ทธ๋ž˜๋„ ๋‹ค์ผ ํ™•์ธ ๊ถŒ์žฅ + - ํ‘œ๋ณธ ์žฅ์ผ: +0.0p โ€” ๊ฑฐ๋ž˜์ผโ‰ˆ5์ผ โ€” ํ‘œ๋ณธ ์ผ์ˆ˜ ์ƒ๋Œ€์  ์–‘ํ˜ธ + - ๊ฑฐ๋ž˜ ํ‘œ๋ณธ: +25.0p โ€” ํ†ต๊ณผ ํ›„๋ณด ์—†์Œ โ€” ์ ์šฉ ๋ถˆ๊ฐ€ + - ์Šน๋ฅ ยทPF ์ด์ƒ์น˜: +0.0p โ€” ์ด์ƒ์น˜ ์—†์Œ + - ๊ฒŒ์ดํŠธ ์ปค๋ฒ„: +8.0p โ€” ํ•™์Šตยทgated ๋ชจ๋‘ ๋น„์–ด ์žˆ์Œ + - PnL ๊ณ ์›: +0.0p โ€” ๊ณ ์› ํŒ์ • ์Šคํ‚ต +- _์ฐธ๊ณ : ๊ณผ์ ํ•ฉ%๋Š” ๊ต์ฐจ๊ฒ€์ฆ ์ ์ˆ˜๊ฐ€ ์•„๋‹ˆ๋ผ ํ‘œ๋ณธยท์ด์ƒ์น˜ยท๊ณ ์› ํœด๋ฆฌ์Šคํ‹ฑ์ž…๋‹ˆ๋‹ค. ์ ์šฉ ๊ฐ€๋Šฅ๋„%=100โˆ’๊ณผ์ ํ•ฉ์œ„ํ—˜%. DB ์ ์šฉ ๋ฒ„ํŠผ ํ™œ์„ฑ ์กฐ๊ฑด(gated PnL>0)๊ณผ๋Š” ๋ณ„๊ฐœ์ž…๋‹ˆ๋‹ค._ + +## ์ตœ์ข… ์„ ํƒ ํ›„๋ณด (๊ทœ์น™ ยท DB ์ ์šฉ ์ „ ํ™•์ธ) +- ์•„๋ž˜๋Š” **์—ญํ• ์ด ๋‹ค๋ฅธ** 4์ข… ํ›„๋ณด์ž…๋‹ˆ๋‹ค. mode Top10 1์œ„ โ‰  ์ต์ ˆ ๋Œ€ํ‘œ ยท **DB 1์ˆœ์œ„๋Š” ์‚ฌํ›„ํ•ฉ๊ฒฉ(gated)** ์ž…๋‹ˆ๋‹ค. +- mode pool: `positive` ยท scoring: `band_proximity_p25_p75` + +### ํ›„๋ณด 4์ข… +- **โ‘  ์‚ฌํ›„ํ•ฉ๊ฒฉ 1์œ„ (apply: gated)**: ์—†์Œ +- **โ‘ก ์•ˆ์ • 1์œ„ (apply: stable)**: ์—†์Œ +- **โ‘ข mode_combo (apply: mode)**: ์—†์Œ (๋ฏธ์‚ฐ์ถœยท๊ตฌ JSON) +- **โ‘ฃ mode Top10 1์œ„ (apply: consensus ยท ๋ฐด๋“œ ์ „ํ˜• trial)**: ์—†์Œ +- mode Top10 meta: pool 0๊ฑด ยท ์ถ• 0๊ฐœ + +### ์ถ”์ฒœ (์ž๋™ ยท confirm ํ•„์ˆ˜) +1. **์‚ฌํ›„ํ•ฉ๊ฒฉ 0๊ฑด โ†’ DB ์ ์šฉ ๋น„๊ถŒ์žฅ.** ํ˜„ํ–‰ DB ์œ ์ง€ + ์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑยท๊ธฐ๊ฐ„ ์žฌ๊ฒ€์ฆ. +- โš  ์•ˆ์ • ๊ฒŒ์ดํŠธ 0๊ฑด โ†’ ์•ˆ์ • Top์€ **์ ์ˆ˜์ˆœ ํด๋ฐฑ** (์•ˆ์ • ๊ฒŒ์ดํŠธ 0๊ฑด โ†’ ํ•™์Šตํ’€ ์•ˆ์ •์ ์ˆ˜์ˆœ TopN (๋งˆ์ด๋„ˆ์Šค PnL ํฌํ•จ ยท ์ƒ๋Œ€๋น„๊ต)) + +## ์ด์ „ ์žฅ์—์„œ๋Š” +- ์‹ค๋งค ๋™๊ธฐ๊ฐ„ ์ฒญ์‚ฐ 26๊ฑด ยท ์Šน๋ฅ  23% ยท ํ•ฉ์‚ฐ PnL -94,593์› (๋ฐฑํ…Œ Optuna์™€ ์ˆซ์ž ๋‹ฌ๋ผ๋„ ์ •์ƒ โ€” ๊ณ ์ŠคํŠธยท์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑ ๊ฒฝ๋กœ ์ฐจ์ด). +- ์ด ๊ธฐ๊ฐ„ ๋ฐฑํ…Œ์—์„œ๋Š” **์œ ์˜๋ฏธํ•œ ํ†ต๊ณผ ์กฐํ•ฉ์ด ๊ฑฐ์˜ ์—†์—ˆ์Šต๋‹ˆ๋‹ค.** ์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑยท์†์ ˆยท์‹œ๊ฐ„์ฐฝ์„ ๋จผ์ € ์ ๊ฒ€ํ•˜์„ธ์š” (๋ŒํŒŒ 0๊ฑด์ด๋ฉด ํŠนํžˆ). + +## ์•ž์œผ๋กœ ์žฅ์—์„œ๋Š” +- **1~2์ผ Optuna best๋ฅผ ๋ฐ”๋กœ ์‹ค๋งค์— ๋„ฃ์ง€ ๋งˆ์„ธ์š”.** ๋‹ค์ผ(โ‰ฅ5๊ฑฐ๋ž˜์ผ) ์žฌ๊ฒ€์ฆยท์›น๋ฐฑํ…Œ 1ํšŒ ํ›„ ๊ฒ€ํ† . +- ์ ์šฉ ์‹œ์—๋Š” `results_gated` ํ›„๋ณด๋งŒ. ํƒ์ƒ‰์šฉ best(objective)์™€ ๋‹ค๋ฅผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. +- ์žฅ์ด ์ข์•„์ง€๊ฑฐ๋‚˜ ๋ณ€๋™์„ฑ์ด ์ปค์ง€๋ฉด: ์†์ ˆยทํŠธ๋ ˆ์ผยท์‹œ๊ฐ„์ฐฝ์ด ๋จผ์ € ๊นจ์ง‘๋‹ˆ๋‹ค. ์Šน๋ฅ  ์ž๋ž‘๋ณด๋‹ค **์†์ ˆ์ด ์‚ด์•„ ์žˆ๋Š”์ง€**๋ฅผ ๋ณด์„ธ์š”. +- ํ˜„์žฌ ์‚ฌํ›„ํ•ฉ๊ฒฉ 0๊ฑด โ†’ ํŒŒ๋ผ๋ฏธํ„ฐ ์œ ์ง€(ํ˜„ํ–‰ DB) + ์œ ๋‹ˆ๋ฒ„์Šค/๋ฐ์ดํ„ฐ ์ ๊ฒ€์ด ์šฐ์„ ์ž…๋‹ˆ๋‹ค. + +_์ƒ์„ฑ: 2026-09-04 14:03:50 (rule)_ + +## AI ์ฝ”๋ฉ˜ํŠธ (์ด์ „ ์žฅ / ์•ž์œผ๋กœ ์žฅ) [gemini] + +**์ด์ „ ์žฅ์—์„œ๋Š”** +์‹ค์ œ ๊ฑฐ๋ž˜์—์„œ๋Š” ์ €์กฐํ•œ ์Šน๋ฅ ๊ณผ ์†์‹ค์ด ๋ฐœ์ƒํ–ˆ์œผ๋ฉฐ, Optuna ๋ฐฑํ…Œ์ŠคํŠธ๋Š” 5์ผ์ด๋ผ๋Š” ์งง์€ ๊ธฐ๊ฐ„ ๋™์•ˆ ์œ ์˜๋ฏธํ•œ ํ•ฉ๊ฒฉ ์กฐํ•ฉ์„ ์ „ํ˜€ ์ฐพ์ง€ ๋ชปํ–ˆ์Šต๋‹ˆ๋‹ค. ๋ฐฑํ…Œ์ŠคํŠธ ๊ฒฐ๊ณผ์™€ ์‹ค๋งค๋Š” ๊ณ ์ŠคํŠธ, ์œ ๋‹ˆ๋ฒ„์Šค, ํ‹ฑ ๊ฒฝ๋กœ ์ฐจ์ด๋กœ ์ธํ•ด ๊ดด๋ฆฌ๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉฐ, ์ด๋Š” ํ˜„์žฌ ํ‘œ๋ณธ ๋ถ€์กฑ๊ณผ ๊ณผ์ ํ•ฉ ์œ„ํ—˜์ด ๋†’์Œ์„ ๊ฒฝ๊ณ ํ•ฉ๋‹ˆ๋‹ค. + +**์•ž์œผ๋กœ ์žฅ์—์„œ๋Š”** +์‚ฌํ›„ํ•ฉ๊ฒฉ(gated)๋œ ์œ ํšจ ์กฐํ•ฉ์ด 0๊ฑด์ด๋ฏ€๋กœ, ์–ด๋–ค ์ „๋žต๋„ ์ฆ‰์‹œ ์‹ค๋งค ์ ์šฉ์„ **๊ฐ•๋ ฅํžˆ ๋น„๊ถŒ์žฅ**ํ•ฉ๋‹ˆ๋‹ค. 5์ผ์˜ ์งง์€ ๊ธฐ๊ฐ„์€ ๊ณผ์ ํ•ฉ ์œ„ํ—˜(ํœด๋ฆฌ์Šคํ‹ฑ์ƒ ์ƒ๋Œ€์  ๋‚ฎ์Œ ํŒ์ •์—๋„ ๋ถˆ๊ตฌํ•˜๊ณ )๊ณผ ํ‘œ๋ณธ ๋ถ€์กฑ ๋ฌธ์ œ๋ฅผ ์•ˆ๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. `mode Top10 1์œ„`๋Š” ์ต์ ˆ ๋Œ€ํ‘œ๊ฐ€ ์•„๋‹ˆ๋ฉฐ, DB 1์ˆœ์œ„๋Š” ์‚ฌํ›„ํ•ฉ๊ฒฉ์ž…๋‹ˆ๋‹ค. ์ ์šฉ ์ „ ๋ฐ˜๋“œ์‹œ ๋‹ค์ผ ์žฌ๊ฒ€์ฆ๊ณผ ์›น๋ฐฑํ…Œ์ŠคํŠธ๋ฅผ ํ†ตํ•ด ๋ฐฑํ…Œ-์‹ค๋งค ๊ดด๋ฆฌ๋ฅผ ํ™•์ธํ•˜๊ณ , ํ˜„ํ–‰ DB ์œ ์ง€์™€ ์œ ๋‹ˆ๋ฒ„์Šค/๋ฐ์ดํ„ฐ ์žฌ์ ๊ฒ€์ด ์šฐ์„ ์ž…๋‹ˆ๋‹ค. diff --git a/kis_trader/backtest/results/optuna_breakout_tpe_20260904_141259.briefing.md b/kis_trader/backtest/results/optuna_breakout_tpe_20260904_141259.briefing.md new file mode 100644 index 0000000..78cb65c --- /dev/null +++ b/kis_trader/backtest/results/optuna_breakout_tpe_20260904_141259.briefing.md @@ -0,0 +1,49 @@ +# Optuna ๋ธŒ๋ฆฌํ•‘ โ€” ๋ŒํŒŒ (tpe) +๊ธฐ๊ฐ„: 2026-08-31 ~ 2026-09-04 (๊ฑฐ๋ž˜์ผโ‰ˆ5์ผ) ยท trials 200/200 +ํƒ์ƒ‰ ๊ฒŒ์ดํŠธ: WRโ‰ฅ0% PFโ‰ฅ0 ยท min_tradesโ‰ฅ10 | ํ›„๋ณด ๊ฒŒ์ดํŠธ: WRโ‰ฅ40% PFโ‰ฅ1 ยท min_tradesโ‰ฅ10 +- min_trades=10: **ํ•ฉ๊ฒฉ ์ธ์ • ์ตœ์†Œ ๊ฑฐ๋ž˜ ๊ฑด์ˆ˜**(ํ‘œ๋ณธ ๋ถ€์กฑยท์šฐ์—ฐ ์Šน๋ฅ  ๋ฐฉ์ง€). ์ด๋ณด๋‹ค ์ ์€ ์กฐํ•ฉ์€ ํ•™์Šต/ํ›„๋ณด ์ง‘๊ณ„์—์„œ ์ œ์™ธ๋ฉ๋‹ˆ๋‹ค. +ํ•™์Šต์šฉ ํ†ต๊ณผ 0๊ฑด ยท ์‚ฌํ›„ํ•ฉ๊ฒฉ(results_gated) 0๊ฑด + +## ๊ณผ์ ํ•ฉยท์ ์šฉ ๊ฐ€๋Šฅ๋„ (ํœด๋ฆฌ์Šคํ‹ฑ) +- **๊ณผ์ ํ•ฉ ์œ„ํ—˜ 33.0%** ยท **์ ์šฉ ๊ฐ€๋Šฅ๋„ 67.0%** ยท ํŒ์ •: **์ƒ๋Œ€์ ์œผ๋กœ๋‚ฎ์Œ** โ€” ํœด๋ฆฌ์Šคํ‹ฑ์ƒ ์œ„ํ—˜ ์ƒ๋Œ€์  ๋‚ฎ์Œ โ€” ๊ทธ๋ž˜๋„ ๋‹ค์ผ ํ™•์ธ ๊ถŒ์žฅ + - ํ‘œ๋ณธ ์žฅ์ผ: +0.0p โ€” ๊ฑฐ๋ž˜์ผโ‰ˆ5์ผ โ€” ํ‘œ๋ณธ ์ผ์ˆ˜ ์ƒ๋Œ€์  ์–‘ํ˜ธ + - ๊ฑฐ๋ž˜ ํ‘œ๋ณธ: +25.0p โ€” ํ†ต๊ณผ ํ›„๋ณด ์—†์Œ โ€” ์ ์šฉ ๋ถˆ๊ฐ€ + - ์Šน๋ฅ ยทPF ์ด์ƒ์น˜: +0.0p โ€” ์ด์ƒ์น˜ ์—†์Œ + - ๊ฒŒ์ดํŠธ ์ปค๋ฒ„: +8.0p โ€” ํ•™์Šตยทgated ๋ชจ๋‘ ๋น„์–ด ์žˆ์Œ + - PnL ๊ณ ์›: +0.0p โ€” ๊ณ ์› ํŒ์ • ์Šคํ‚ต +- _์ฐธ๊ณ : ๊ณผ์ ํ•ฉ%๋Š” ๊ต์ฐจ๊ฒ€์ฆ ์ ์ˆ˜๊ฐ€ ์•„๋‹ˆ๋ผ ํ‘œ๋ณธยท์ด์ƒ์น˜ยท๊ณ ์› ํœด๋ฆฌ์Šคํ‹ฑ์ž…๋‹ˆ๋‹ค. ์ ์šฉ ๊ฐ€๋Šฅ๋„%=100โˆ’๊ณผ์ ํ•ฉ์œ„ํ—˜%. DB ์ ์šฉ ๋ฒ„ํŠผ ํ™œ์„ฑ ์กฐ๊ฑด(gated PnL>0)๊ณผ๋Š” ๋ณ„๊ฐœ์ž…๋‹ˆ๋‹ค._ + +## ์ตœ์ข… ์„ ํƒ ํ›„๋ณด (๊ทœ์น™ ยท DB ์ ์šฉ ์ „ ํ™•์ธ) +- ์•„๋ž˜๋Š” **์—ญํ• ์ด ๋‹ค๋ฅธ** 4์ข… ํ›„๋ณด์ž…๋‹ˆ๋‹ค. mode Top10 1์œ„ โ‰  ์ต์ ˆ ๋Œ€ํ‘œ ยท **DB 1์ˆœ์œ„๋Š” ์‚ฌํ›„ํ•ฉ๊ฒฉ(gated)** ์ž…๋‹ˆ๋‹ค. +- mode pool: `positive` ยท scoring: `band_proximity_p25_p75` + +### ํ›„๋ณด 4์ข… +- **โ‘  ์‚ฌํ›„ํ•ฉ๊ฒฉ 1์œ„ (apply: gated)**: ์—†์Œ +- **โ‘ก ์•ˆ์ • 1์œ„ (apply: stable)**: ์—†์Œ +- **โ‘ข mode_combo (apply: mode)**: ์—†์Œ (๋ฏธ์‚ฐ์ถœยท๊ตฌ JSON) +- **โ‘ฃ mode Top10 1์œ„ (apply: consensus ยท ๋ฐด๋“œ ์ „ํ˜• trial)**: ์—†์Œ +- mode Top10 meta: pool 0๊ฑด ยท ์ถ• 0๊ฐœ + +### ์ถ”์ฒœ (์ž๋™ ยท confirm ํ•„์ˆ˜) +1. **์‚ฌํ›„ํ•ฉ๊ฒฉ 0๊ฑด โ†’ DB ์ ์šฉ ๋น„๊ถŒ์žฅ.** ํ˜„ํ–‰ DB ์œ ์ง€ + ์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑยท๊ธฐ๊ฐ„ ์žฌ๊ฒ€์ฆ. +- โš  ์•ˆ์ • ๊ฒŒ์ดํŠธ 0๊ฑด โ†’ ์•ˆ์ • Top์€ **์ ์ˆ˜์ˆœ ํด๋ฐฑ** (์•ˆ์ • ๊ฒŒ์ดํŠธ 0๊ฑด โ†’ ํ•™์Šตํ’€ ์•ˆ์ •์ ์ˆ˜์ˆœ TopN (๋งˆ์ด๋„ˆ์Šค PnL ํฌํ•จ ยท ์ƒ๋Œ€๋น„๊ต)) + +## ์ด์ „ ์žฅ์—์„œ๋Š” +- ์‹ค๋งค ๋™๊ธฐ๊ฐ„ ์ฒญ์‚ฐ 26๊ฑด ยท ์Šน๋ฅ  23% ยท ํ•ฉ์‚ฐ PnL -94,593์› (๋ฐฑํ…Œ Optuna์™€ ์ˆซ์ž ๋‹ฌ๋ผ๋„ ์ •์ƒ โ€” ๊ณ ์ŠคํŠธยท์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑ ๊ฒฝ๋กœ ์ฐจ์ด). +- ์ด ๊ธฐ๊ฐ„ ๋ฐฑํ…Œ์—์„œ๋Š” **์œ ์˜๋ฏธํ•œ ํ†ต๊ณผ ์กฐํ•ฉ์ด ๊ฑฐ์˜ ์—†์—ˆ์Šต๋‹ˆ๋‹ค.** ์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑยท์†์ ˆยท์‹œ๊ฐ„์ฐฝ์„ ๋จผ์ € ์ ๊ฒ€ํ•˜์„ธ์š” (๋ŒํŒŒ 0๊ฑด์ด๋ฉด ํŠนํžˆ). + +## ์•ž์œผ๋กœ ์žฅ์—์„œ๋Š” +- **1~2์ผ Optuna best๋ฅผ ๋ฐ”๋กœ ์‹ค๋งค์— ๋„ฃ์ง€ ๋งˆ์„ธ์š”.** ๋‹ค์ผ(โ‰ฅ5๊ฑฐ๋ž˜์ผ) ์žฌ๊ฒ€์ฆยท์›น๋ฐฑํ…Œ 1ํšŒ ํ›„ ๊ฒ€ํ† . +- ์ ์šฉ ์‹œ์—๋Š” `results_gated` ํ›„๋ณด๋งŒ. ํƒ์ƒ‰์šฉ best(objective)์™€ ๋‹ค๋ฅผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. +- ์žฅ์ด ์ข์•„์ง€๊ฑฐ๋‚˜ ๋ณ€๋™์„ฑ์ด ์ปค์ง€๋ฉด: ์†์ ˆยทํŠธ๋ ˆ์ผยท์‹œ๊ฐ„์ฐฝ์ด ๋จผ์ € ๊นจ์ง‘๋‹ˆ๋‹ค. ์Šน๋ฅ  ์ž๋ž‘๋ณด๋‹ค **์†์ ˆ์ด ์‚ด์•„ ์žˆ๋Š”์ง€**๋ฅผ ๋ณด์„ธ์š”. +- ํ˜„์žฌ ์‚ฌํ›„ํ•ฉ๊ฒฉ 0๊ฑด โ†’ ํŒŒ๋ผ๋ฏธํ„ฐ ์œ ์ง€(ํ˜„ํ–‰ DB) + ์œ ๋‹ˆ๋ฒ„์Šค/๋ฐ์ดํ„ฐ ์ ๊ฒ€์ด ์šฐ์„ ์ž…๋‹ˆ๋‹ค. + +_์ƒ์„ฑ: 2026-09-04 14:12:59 (rule)_ + +## AI ์ฝ”๋ฉ˜ํŠธ (์ด์ „ ์žฅ / ์•ž์œผ๋กœ ์žฅ) [gemini] + +**์ด์ „ ์žฅ์—์„œ๋Š”** +์ง€๋‚œ 5๊ฑฐ๋ž˜์ผ ์‹ค๋งค๋Š” ์Šน๋ฅ  23%, ์•ฝ 9๋งŒ์› ์†์‹ค์ด์—ˆ์Šต๋‹ˆ๋‹ค. ๋ฐฑํ…Œ์ŠคํŠธ ์—ญ์‹œ `min_trades=10` ๊ฒŒ์ดํŠธ ํ†ต๊ณผ ์ „๋žต์ด ์ „๋ฌดํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” ์งง์€ ๊ธฐ๊ฐ„์œผ๋กœ ์ธํ•œ **ํ‘œ๋ณธ ๋ถ€์กฑ**๊ณผ **์‹ค๋งคโ†”๋ฐฑํ…Œ ๊ดด๋ฆฌ**๊ฐ€ ์ปธ์Œ์„ ๋ช…ํ™•ํžˆ ์‹œ์‚ฌํ•ฉ๋‹ˆ๋‹ค. + +**์•ž์œผ๋กœ ์žฅ์—์„œ๋Š”** +์ด๋ฒˆ Optuna๋Š” **์‚ฌํ›„ํ•ฉ๊ฒฉ(gated) ์ „๋žต์ด ์—†์–ด** ์‹ค๋งค ์ ์šฉ์ด ๋ถˆ๊ฐ€ํ•˜๋ฉฐ, **๊ณผ์ ํ•ฉยทํ‘œ๋ณธ ๋ถ€์กฑ ์œ„ํ—˜**์ด ๋งค์šฐ ๋†’์Šต๋‹ˆ๋‹ค. 5์ผ ๋ฐ์ดํ„ฐ๋Š” ์‹ ๋ขฐํ•˜๊ธฐ ์–ด๋ ต์Šต๋‹ˆ๋‹ค. `mode Top10 1์œ„`๋ฅผ ์ต์ ˆ ๋Œ€ํ‘œ๋กœ ๋‹จ์ •ํ•ด ๋ฐ”๋กœ ์ ์šฉ ๋งˆ์‹ญ์‹œ์˜ค. ์‹ค๋งคโ†”๋ฐฑํ…Œ ๊ดด๋ฆฌ(๊ณ ์ŠคํŠธํผ์ง€ ๋“ฑ)๋Š” ์ƒ์กดํ•ฉ๋‹ˆ๋‹ค. **ํ˜„ํ–‰ DB ์œ ์ง€ ๋ฐ ์œ ๋‹ˆ๋ฒ„์Šค/๋ฐ์ดํ„ฐ/๊ธฐ๊ฐ„ ์žฌ๊ฒ€ํ† **๊ฐ€ ์šฐ์„ ์ž…๋‹ˆ๋‹ค. ํŠน์ • ์ข…๋ชฉ ๋งค์ˆ˜ ์ถ”์ฒœ์ด๋‚˜ ํ™•์ • ์ˆ˜์ต ์•ฝ์†์€ ๋ถˆ๊ฐ€ํ•ฉ๋‹ˆ๋‹ค. diff --git a/kis_trader/backtest/results/optuna_breakout_tpe_20260904_142157.briefing.md b/kis_trader/backtest/results/optuna_breakout_tpe_20260904_142157.briefing.md new file mode 100644 index 0000000..5caba93 --- /dev/null +++ b/kis_trader/backtest/results/optuna_breakout_tpe_20260904_142157.briefing.md @@ -0,0 +1,49 @@ +# Optuna ๋ธŒ๋ฆฌํ•‘ โ€” ๋ŒํŒŒ (tpe) +๊ธฐ๊ฐ„: 2026-08-31 ~ 2026-09-04 (๊ฑฐ๋ž˜์ผโ‰ˆ5์ผ) ยท trials 200/200 +ํƒ์ƒ‰ ๊ฒŒ์ดํŠธ: WRโ‰ฅ0% PFโ‰ฅ0 ยท min_tradesโ‰ฅ10 | ํ›„๋ณด ๊ฒŒ์ดํŠธ: WRโ‰ฅ40% PFโ‰ฅ1 ยท min_tradesโ‰ฅ10 +- min_trades=10: **ํ•ฉ๊ฒฉ ์ธ์ • ์ตœ์†Œ ๊ฑฐ๋ž˜ ๊ฑด์ˆ˜**(ํ‘œ๋ณธ ๋ถ€์กฑยท์šฐ์—ฐ ์Šน๋ฅ  ๋ฐฉ์ง€). ์ด๋ณด๋‹ค ์ ์€ ์กฐํ•ฉ์€ ํ•™์Šต/ํ›„๋ณด ์ง‘๊ณ„์—์„œ ์ œ์™ธ๋ฉ๋‹ˆ๋‹ค. +ํ•™์Šต์šฉ ํ†ต๊ณผ 0๊ฑด ยท ์‚ฌํ›„ํ•ฉ๊ฒฉ(results_gated) 0๊ฑด + +## ๊ณผ์ ํ•ฉยท์ ์šฉ ๊ฐ€๋Šฅ๋„ (ํœด๋ฆฌ์Šคํ‹ฑ) +- **๊ณผ์ ํ•ฉ ์œ„ํ—˜ 33.0%** ยท **์ ์šฉ ๊ฐ€๋Šฅ๋„ 67.0%** ยท ํŒ์ •: **์ƒ๋Œ€์ ์œผ๋กœ๋‚ฎ์Œ** โ€” ํœด๋ฆฌ์Šคํ‹ฑ์ƒ ์œ„ํ—˜ ์ƒ๋Œ€์  ๋‚ฎ์Œ โ€” ๊ทธ๋ž˜๋„ ๋‹ค์ผ ํ™•์ธ ๊ถŒ์žฅ + - ํ‘œ๋ณธ ์žฅ์ผ: +0.0p โ€” ๊ฑฐ๋ž˜์ผโ‰ˆ5์ผ โ€” ํ‘œ๋ณธ ์ผ์ˆ˜ ์ƒ๋Œ€์  ์–‘ํ˜ธ + - ๊ฑฐ๋ž˜ ํ‘œ๋ณธ: +25.0p โ€” ํ†ต๊ณผ ํ›„๋ณด ์—†์Œ โ€” ์ ์šฉ ๋ถˆ๊ฐ€ + - ์Šน๋ฅ ยทPF ์ด์ƒ์น˜: +0.0p โ€” ์ด์ƒ์น˜ ์—†์Œ + - ๊ฒŒ์ดํŠธ ์ปค๋ฒ„: +8.0p โ€” ํ•™์Šตยทgated ๋ชจ๋‘ ๋น„์–ด ์žˆ์Œ + - PnL ๊ณ ์›: +0.0p โ€” ๊ณ ์› ํŒ์ • ์Šคํ‚ต +- _์ฐธ๊ณ : ๊ณผ์ ํ•ฉ%๋Š” ๊ต์ฐจ๊ฒ€์ฆ ์ ์ˆ˜๊ฐ€ ์•„๋‹ˆ๋ผ ํ‘œ๋ณธยท์ด์ƒ์น˜ยท๊ณ ์› ํœด๋ฆฌ์Šคํ‹ฑ์ž…๋‹ˆ๋‹ค. ์ ์šฉ ๊ฐ€๋Šฅ๋„%=100โˆ’๊ณผ์ ํ•ฉ์œ„ํ—˜%. DB ์ ์šฉ ๋ฒ„ํŠผ ํ™œ์„ฑ ์กฐ๊ฑด(gated PnL>0)๊ณผ๋Š” ๋ณ„๊ฐœ์ž…๋‹ˆ๋‹ค._ + +## ์ตœ์ข… ์„ ํƒ ํ›„๋ณด (๊ทœ์น™ ยท DB ์ ์šฉ ์ „ ํ™•์ธ) +- ์•„๋ž˜๋Š” **์—ญํ• ์ด ๋‹ค๋ฅธ** 4์ข… ํ›„๋ณด์ž…๋‹ˆ๋‹ค. mode Top10 1์œ„ โ‰  ์ต์ ˆ ๋Œ€ํ‘œ ยท **DB 1์ˆœ์œ„๋Š” ์‚ฌํ›„ํ•ฉ๊ฒฉ(gated)** ์ž…๋‹ˆ๋‹ค. +- mode pool: `positive` ยท scoring: `band_proximity_p25_p75` + +### ํ›„๋ณด 4์ข… +- **โ‘  ์‚ฌํ›„ํ•ฉ๊ฒฉ 1์œ„ (apply: gated)**: ์—†์Œ +- **โ‘ก ์•ˆ์ • 1์œ„ (apply: stable)**: ์—†์Œ +- **โ‘ข mode_combo (apply: mode)**: ์—†์Œ (๋ฏธ์‚ฐ์ถœยท๊ตฌ JSON) +- **โ‘ฃ mode Top10 1์œ„ (apply: consensus ยท ๋ฐด๋“œ ์ „ํ˜• trial)**: ์—†์Œ +- mode Top10 meta: pool 0๊ฑด ยท ์ถ• 0๊ฐœ + +### ์ถ”์ฒœ (์ž๋™ ยท confirm ํ•„์ˆ˜) +1. **์‚ฌํ›„ํ•ฉ๊ฒฉ 0๊ฑด โ†’ DB ์ ์šฉ ๋น„๊ถŒ์žฅ.** ํ˜„ํ–‰ DB ์œ ์ง€ + ์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑยท๊ธฐ๊ฐ„ ์žฌ๊ฒ€์ฆ. +- โš  ์•ˆ์ • ๊ฒŒ์ดํŠธ 0๊ฑด โ†’ ์•ˆ์ • Top์€ **์ ์ˆ˜์ˆœ ํด๋ฐฑ** (์•ˆ์ • ๊ฒŒ์ดํŠธ 0๊ฑด โ†’ ํ•™์Šตํ’€ ์•ˆ์ •์ ์ˆ˜์ˆœ TopN (๋งˆ์ด๋„ˆ์Šค PnL ํฌํ•จ ยท ์ƒ๋Œ€๋น„๊ต)) + +## ์ด์ „ ์žฅ์—์„œ๋Š” +- ์‹ค๋งค ๋™๊ธฐ๊ฐ„ ์ฒญ์‚ฐ 26๊ฑด ยท ์Šน๋ฅ  23% ยท ํ•ฉ์‚ฐ PnL -94,593์› (๋ฐฑํ…Œ Optuna์™€ ์ˆซ์ž ๋‹ฌ๋ผ๋„ ์ •์ƒ โ€” ๊ณ ์ŠคํŠธยท์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑ ๊ฒฝ๋กœ ์ฐจ์ด). +- ์ด ๊ธฐ๊ฐ„ ๋ฐฑํ…Œ์—์„œ๋Š” **์œ ์˜๋ฏธํ•œ ํ†ต๊ณผ ์กฐํ•ฉ์ด ๊ฑฐ์˜ ์—†์—ˆ์Šต๋‹ˆ๋‹ค.** ์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑยท์†์ ˆยท์‹œ๊ฐ„์ฐฝ์„ ๋จผ์ € ์ ๊ฒ€ํ•˜์„ธ์š” (๋ŒํŒŒ 0๊ฑด์ด๋ฉด ํŠนํžˆ). + +## ์•ž์œผ๋กœ ์žฅ์—์„œ๋Š” +- **1~2์ผ Optuna best๋ฅผ ๋ฐ”๋กœ ์‹ค๋งค์— ๋„ฃ์ง€ ๋งˆ์„ธ์š”.** ๋‹ค์ผ(โ‰ฅ5๊ฑฐ๋ž˜์ผ) ์žฌ๊ฒ€์ฆยท์›น๋ฐฑํ…Œ 1ํšŒ ํ›„ ๊ฒ€ํ† . +- ์ ์šฉ ์‹œ์—๋Š” `results_gated` ํ›„๋ณด๋งŒ. ํƒ์ƒ‰์šฉ best(objective)์™€ ๋‹ค๋ฅผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. +- ์žฅ์ด ์ข์•„์ง€๊ฑฐ๋‚˜ ๋ณ€๋™์„ฑ์ด ์ปค์ง€๋ฉด: ์†์ ˆยทํŠธ๋ ˆ์ผยท์‹œ๊ฐ„์ฐฝ์ด ๋จผ์ € ๊นจ์ง‘๋‹ˆ๋‹ค. ์Šน๋ฅ  ์ž๋ž‘๋ณด๋‹ค **์†์ ˆ์ด ์‚ด์•„ ์žˆ๋Š”์ง€**๋ฅผ ๋ณด์„ธ์š”. +- ํ˜„์žฌ ์‚ฌํ›„ํ•ฉ๊ฒฉ 0๊ฑด โ†’ ํŒŒ๋ผ๋ฏธํ„ฐ ์œ ์ง€(ํ˜„ํ–‰ DB) + ์œ ๋‹ˆ๋ฒ„์Šค/๋ฐ์ดํ„ฐ ์ ๊ฒ€์ด ์šฐ์„ ์ž…๋‹ˆ๋‹ค. + +_์ƒ์„ฑ: 2026-09-04 14:21:57 (rule)_ + +## AI ์ฝ”๋ฉ˜ํŠธ (์ด์ „ ์žฅ / ์•ž์œผ๋กœ ์žฅ) [gemini] + +**์ด์ „ ์žฅ์—์„œ๋Š”** +์ง€๋‚œ ๊ธฐ๊ฐ„ ์‹ค๋งค์—์„œ๋Š” 26๊ฑด ์ฒญ์‚ฐ์— ์Šน๋ฅ  23%, ํ•ฉ์‚ฐ PnL -94,593์›์„ ๊ธฐ๋กํ–ˆ์Šต๋‹ˆ๋‹ค. ๋ฐฑํ…Œ์ŠคํŠธ Optuna ๊ฒฐ๊ณผ์™€ ์‹ค๋งค ์ˆซ์ž๋Š” ๊ณ ์ŠคํŠธํผ์ง€ ๋“ฑ ์š”์ธ์œผ๋กœ ๋‹ค๋ฅผ ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์ด ๊ธฐ๊ฐ„ Optuna ํƒ์ƒ‰์—์„œ๋Š” ์ตœ์†Œ ๊ฑฐ๋ž˜ ๊ฑด์ˆ˜(10๊ฑด)๋ฅผ ๋งŒ์กฑํ•˜๋Š” ์œ ์˜๋ฏธํ•œ ํ•ฉ๊ฒฉ ์กฐํ•ฉ์ด ์ „ํ˜€ ์—†์—ˆ์Šต๋‹ˆ๋‹ค. ์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑยท์†์ ˆ ๋“ฑ ์ „๋žต ์žฌ์ ๊ฒ€์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. + +**์•ž์œผ๋กœ ์žฅ์—์„œ๋Š”** +์‚ฌํ›„ํ•ฉ๊ฒฉ ์กฐํ•ฉ์ด 0๊ฑด์ด๋ฏ€๋กœ, **ํ˜„์žฌ ๋ฐฑํ…Œ์ŠคํŠธ ๊ฒฐ๊ณผ๋ฅผ ์‹ค๋งค์— ์ ์šฉํ•˜๋Š” ๊ฒƒ์€ ๊ถŒ์žฅํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.** 5๊ฑฐ๋ž˜์ผ์ด๋ผ๋Š” ์งง์€ ๊ธฐ๊ฐ„์˜ ๊ฒฐ๊ณผ๋Š” ๊ณผ์ ํ•ฉ ๋ฐ ํ‘œ๋ณธ ๋ถ€์กฑ ์œ„ํ—˜์ด ๋งค์šฐ ํฌ๋ฉฐ, ๋ฐฑํ…Œ์ŠคํŠธ์™€ ์‹ค์ œ ์‹œ์žฅ ๊ดด๋ฆฌ(๊ณ ์ŠคํŠธํผ์ง€)๋„ ํ•ญ์ƒ ์—ผ๋‘์— ๋‘์‹ญ์‹œ์˜ค. DB 1์ˆœ์œ„๊ฐ€ ์ต์ ˆ์„ ๋ณด์žฅํ•˜์ง€ ์•Š์œผ๋ฉฐ, ํŠน์ • ์ข…๋ชฉ ๋งค์ˆ˜ ์ถ”์ฒœ์ด๋‚˜ ํ™•์ • ์ˆ˜์ต์€ ๋ถˆ๊ฐ€ํ•ฉ๋‹ˆ๋‹ค. ์šฐ์„  ํ˜„ํ–‰ DB๋ฅผ ์œ ์ง€ํ•˜๋ฉฐ ์œ ๋‹ˆ๋ฒ„์Šค ๋ฐ ๋ฐ์ดํ„ฐ ์ ๊ฒ€์„ ๋จผ์ € ์ˆ˜ํ–‰ํ•ด ์ฃผ์‹ญ์‹œ์˜ค. diff --git a/kis_trader/backtest/results/optuna_breakout_tpe_20260904_152040.briefing.md b/kis_trader/backtest/results/optuna_breakout_tpe_20260904_152040.briefing.md new file mode 100644 index 0000000..cbb3c40 --- /dev/null +++ b/kis_trader/backtest/results/optuna_breakout_tpe_20260904_152040.briefing.md @@ -0,0 +1,49 @@ +# Optuna ๋ธŒ๋ฆฌํ•‘ โ€” ๋ŒํŒŒ (tpe) +๊ธฐ๊ฐ„: 2026-08-31 ~ 2026-09-04 (๊ฑฐ๋ž˜์ผโ‰ˆ5์ผ) ยท trials 200/200 +ํƒ์ƒ‰ ๊ฒŒ์ดํŠธ: WRโ‰ฅ0% PFโ‰ฅ0 ยท min_tradesโ‰ฅ10 | ํ›„๋ณด ๊ฒŒ์ดํŠธ: WRโ‰ฅ40% PFโ‰ฅ1 ยท min_tradesโ‰ฅ10 +- min_trades=10: **ํ•ฉ๊ฒฉ ์ธ์ • ์ตœ์†Œ ๊ฑฐ๋ž˜ ๊ฑด์ˆ˜**(ํ‘œ๋ณธ ๋ถ€์กฑยท์šฐ์—ฐ ์Šน๋ฅ  ๋ฐฉ์ง€). ์ด๋ณด๋‹ค ์ ์€ ์กฐํ•ฉ์€ ํ•™์Šต/ํ›„๋ณด ์ง‘๊ณ„์—์„œ ์ œ์™ธ๋ฉ๋‹ˆ๋‹ค. +ํ•™์Šต์šฉ ํ†ต๊ณผ 0๊ฑด ยท ์‚ฌํ›„ํ•ฉ๊ฒฉ(results_gated) 0๊ฑด + +## ๊ณผ์ ํ•ฉยท์ ์šฉ ๊ฐ€๋Šฅ๋„ (ํœด๋ฆฌ์Šคํ‹ฑ) +- **๊ณผ์ ํ•ฉ ์œ„ํ—˜ 33.0%** ยท **์ ์šฉ ๊ฐ€๋Šฅ๋„ 67.0%** ยท ํŒ์ •: **์ƒ๋Œ€์ ์œผ๋กœ๋‚ฎ์Œ** โ€” ํœด๋ฆฌ์Šคํ‹ฑ์ƒ ์œ„ํ—˜ ์ƒ๋Œ€์  ๋‚ฎ์Œ โ€” ๊ทธ๋ž˜๋„ ๋‹ค์ผ ํ™•์ธ ๊ถŒ์žฅ + - ํ‘œ๋ณธ ์žฅ์ผ: +0.0p โ€” ๊ฑฐ๋ž˜์ผโ‰ˆ5์ผ โ€” ํ‘œ๋ณธ ์ผ์ˆ˜ ์ƒ๋Œ€์  ์–‘ํ˜ธ + - ๊ฑฐ๋ž˜ ํ‘œ๋ณธ: +25.0p โ€” ํ†ต๊ณผ ํ›„๋ณด ์—†์Œ โ€” ์ ์šฉ ๋ถˆ๊ฐ€ + - ์Šน๋ฅ ยทPF ์ด์ƒ์น˜: +0.0p โ€” ์ด์ƒ์น˜ ์—†์Œ + - ๊ฒŒ์ดํŠธ ์ปค๋ฒ„: +8.0p โ€” ํ•™์Šตยทgated ๋ชจ๋‘ ๋น„์–ด ์žˆ์Œ + - PnL ๊ณ ์›: +0.0p โ€” ๊ณ ์› ํŒ์ • ์Šคํ‚ต +- _์ฐธ๊ณ : ๊ณผ์ ํ•ฉ%๋Š” ๊ต์ฐจ๊ฒ€์ฆ ์ ์ˆ˜๊ฐ€ ์•„๋‹ˆ๋ผ ํ‘œ๋ณธยท์ด์ƒ์น˜ยท๊ณ ์› ํœด๋ฆฌ์Šคํ‹ฑ์ž…๋‹ˆ๋‹ค. ์ ์šฉ ๊ฐ€๋Šฅ๋„%=100โˆ’๊ณผ์ ํ•ฉ์œ„ํ—˜%. DB ์ ์šฉ ๋ฒ„ํŠผ ํ™œ์„ฑ ์กฐ๊ฑด(gated PnL>0)๊ณผ๋Š” ๋ณ„๊ฐœ์ž…๋‹ˆ๋‹ค._ + +## ์ตœ์ข… ์„ ํƒ ํ›„๋ณด (๊ทœ์น™ ยท DB ์ ์šฉ ์ „ ํ™•์ธ) +- ์•„๋ž˜๋Š” **์—ญํ• ์ด ๋‹ค๋ฅธ** 4์ข… ํ›„๋ณด์ž…๋‹ˆ๋‹ค. mode Top10 1์œ„ โ‰  ์ต์ ˆ ๋Œ€ํ‘œ ยท **DB 1์ˆœ์œ„๋Š” ์‚ฌํ›„ํ•ฉ๊ฒฉ(gated)** ์ž…๋‹ˆ๋‹ค. +- mode pool: `positive` ยท scoring: `band_proximity_p25_p75` + +### ํ›„๋ณด 4์ข… +- **โ‘  ์‚ฌํ›„ํ•ฉ๊ฒฉ 1์œ„ (apply: gated)**: ์—†์Œ +- **โ‘ก ์•ˆ์ • 1์œ„ (apply: stable)**: ์—†์Œ +- **โ‘ข mode_combo (apply: mode)**: ์—†์Œ (๋ฏธ์‚ฐ์ถœยท๊ตฌ JSON) +- **โ‘ฃ mode Top10 1์œ„ (apply: consensus ยท ๋ฐด๋“œ ์ „ํ˜• trial)**: ์—†์Œ +- mode Top10 meta: pool 0๊ฑด ยท ์ถ• 0๊ฐœ + +### ์ถ”์ฒœ (์ž๋™ ยท confirm ํ•„์ˆ˜) +1. **์‚ฌํ›„ํ•ฉ๊ฒฉ 0๊ฑด โ†’ DB ์ ์šฉ ๋น„๊ถŒ์žฅ.** ํ˜„ํ–‰ DB ์œ ์ง€ + ์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑยท๊ธฐ๊ฐ„ ์žฌ๊ฒ€์ฆ. +- โš  ์•ˆ์ • ๊ฒŒ์ดํŠธ 0๊ฑด โ†’ ์•ˆ์ • Top์€ **์ ์ˆ˜์ˆœ ํด๋ฐฑ** (์•ˆ์ • ๊ฒŒ์ดํŠธ 0๊ฑด โ†’ ํ•™์Šตํ’€ ์•ˆ์ •์ ์ˆ˜์ˆœ TopN (๋งˆ์ด๋„ˆ์Šค PnL ํฌํ•จ ยท ์ƒ๋Œ€๋น„๊ต)) + +## ์ด์ „ ์žฅ์—์„œ๋Š” +- ์‹ค๋งค ๋™๊ธฐ๊ฐ„ ์ฒญ์‚ฐ 30๊ฑด ยท ์Šน๋ฅ  27% ยท ํ•ฉ์‚ฐ PnL -82,108์› (๋ฐฑํ…Œ Optuna์™€ ์ˆซ์ž ๋‹ฌ๋ผ๋„ ์ •์ƒ โ€” ๊ณ ์ŠคํŠธยท์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑ ๊ฒฝ๋กœ ์ฐจ์ด). +- ์ด ๊ธฐ๊ฐ„ ๋ฐฑํ…Œ์—์„œ๋Š” **์œ ์˜๋ฏธํ•œ ํ†ต๊ณผ ์กฐํ•ฉ์ด ๊ฑฐ์˜ ์—†์—ˆ์Šต๋‹ˆ๋‹ค.** ์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑยท์†์ ˆยท์‹œ๊ฐ„์ฐฝ์„ ๋จผ์ € ์ ๊ฒ€ํ•˜์„ธ์š” (๋ŒํŒŒ 0๊ฑด์ด๋ฉด ํŠนํžˆ). + +## ์•ž์œผ๋กœ ์žฅ์—์„œ๋Š” +- **1~2์ผ Optuna best๋ฅผ ๋ฐ”๋กœ ์‹ค๋งค์— ๋„ฃ์ง€ ๋งˆ์„ธ์š”.** ๋‹ค์ผ(โ‰ฅ5๊ฑฐ๋ž˜์ผ) ์žฌ๊ฒ€์ฆยท์›น๋ฐฑํ…Œ 1ํšŒ ํ›„ ๊ฒ€ํ† . +- ์ ์šฉ ์‹œ์—๋Š” `results_gated` ํ›„๋ณด๋งŒ. ํƒ์ƒ‰์šฉ best(objective)์™€ ๋‹ค๋ฅผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. +- ์žฅ์ด ์ข์•„์ง€๊ฑฐ๋‚˜ ๋ณ€๋™์„ฑ์ด ์ปค์ง€๋ฉด: ์†์ ˆยทํŠธ๋ ˆ์ผยท์‹œ๊ฐ„์ฐฝ์ด ๋จผ์ € ๊นจ์ง‘๋‹ˆ๋‹ค. ์Šน๋ฅ  ์ž๋ž‘๋ณด๋‹ค **์†์ ˆ์ด ์‚ด์•„ ์žˆ๋Š”์ง€**๋ฅผ ๋ณด์„ธ์š”. +- ํ˜„์žฌ ์‚ฌํ›„ํ•ฉ๊ฒฉ 0๊ฑด โ†’ ํŒŒ๋ผ๋ฏธํ„ฐ ์œ ์ง€(ํ˜„ํ–‰ DB) + ์œ ๋‹ˆ๋ฒ„์Šค/๋ฐ์ดํ„ฐ ์ ๊ฒ€์ด ์šฐ์„ ์ž…๋‹ˆ๋‹ค. + +_์ƒ์„ฑ: 2026-09-04 15:20:40 (rule)_ + +## AI ์ฝ”๋ฉ˜ํŠธ (์ด์ „ ์žฅ / ์•ž์œผ๋กœ ์žฅ) [gemini] + +ใ€Œ์ด์ „ ์žฅ์—์„œ๋Š”ใ€ +์‹ค๋งค์—์„œ๋Š” 30๊ฑด ์ฒญ์‚ฐ์— ์Šน๋ฅ  27%, -8๋งŒ์›๋Œ€ PnL์„ ๊ธฐ๋กํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์ด๋ฒˆ 5๊ฑฐ๋ž˜์ผ ๋ฐฑํ…Œ์ŠคํŠธ์—์„œ๋Š” ์–ด๋–ค ์œ ํšจํ•œ ์ „๋žต ์กฐํ•ฉ๋„ ์ฐพ์ง€ ๋ชปํ–ˆ์Šต๋‹ˆ๋‹ค. 5์ผ์ด๋ผ๋Š” ์งง์€ ๊ธฐ๊ฐ„์€ ํ‘œ๋ณธ ๋ถ€์กฑ ์œ„ํ—˜์ด ๋งค์šฐ ํฌ๋ฉฐ, ๊ณผ์ ํ•ฉ์ด๋‚˜ ์šฐ์—ฐ์˜ ๊ฒฐ๊ณผ์ผ ๊ฐ€๋Šฅ์„ฑ์ด ๋†’์Šต๋‹ˆ๋‹ค. ์‹ค๋งค ๊ฒฐ๊ณผ์™€ ๋ฐฑํ…Œ๋Š” ๋Š˜ ์ฐจ์ด๊ฐ€ ์žˆ์œผ๋‹ˆ, ๊ณ ์ŠคํŠธ ํผ์ง€ ๋“ฑ์˜ ๊ดด๋ฆฌ๋ฅผ ์—ผ๋‘์— ๋‘์„ธ์š”. + +ใ€Œ์•ž์œผ๋กœ ์žฅ์—์„œ๋Š”ใ€ +์ด๋ฒˆ 5์ผ ๋ฐฑํ…Œ์ŠคํŠธ์—์„œ ์œ ํšจํ•œ ์ „๋žต ์กฐํ•ฉ์ด ์—†์–ด, ์–ด๋–ค ์ ์šฉ๋„ ๋น„๊ถŒ์žฅํ•ฉ๋‹ˆ๋‹ค. ์งง์€ ๊ธฐ๊ฐ„๊ณผ ํ†ต๊ณผ 0๊ฑด์€ ๊ณผ์ ํ•ฉ ๋ฐ ํ‘œ๋ณธ ๋ถ€์กฑ ์œ„ํ—˜์ด ๋งค์šฐ ๋†’์Šต๋‹ˆ๋‹ค. mode Top10 1์œ„๊ฐ€ ์ต์ ˆ ๋Œ€ํ‘œ๋Š” ์•„๋‹ˆ๋ฉฐ, ์‹ค์ œ ์ ์šฉ์€ '์‚ฌํ›„ํ•ฉ๊ฒฉ(gated)' ์ „๋žต๋ฟ์ธ๋ฐ, ํ˜„์žฌ๋Š” ์—†์Šต๋‹ˆ๋‹ค. ์‹ค๋งค์™€ ๋ฐฑํ…Œ ๊ฐ„ ๊ดด๋ฆฌ(๊ณ ์ŠคํŠธ ํผ์ง€ ๋“ฑ)๋ฅผ ํ•ญ์ƒ ๊ฒฝ๊ณ ํ•˜๋ฉฐ, ํ™•์ • ์ˆ˜์ต์€ ๋ถˆ๊ฐ€ํ•ฉ๋‹ˆ๋‹ค. ํ˜„ํ–‰ ํŒŒ๋ผ๋ฏธํ„ฐ ์œ ์ง€ ํ›„, ์œ ๋‹ˆ๋ฒ„์Šค/๋ฐ์ดํ„ฐ ๊ธฐ๊ฐ„/์†์ ˆ ๋กœ์ง์„ ์žฌ๊ฒ€์ฆํ•˜๋Š” ๊ฒƒ์ด ์šฐ์„ ์ž…๋‹ˆ๋‹ค. diff --git a/kis_trader/backtest/results/optuna_breakout_tpe_20260904_152752.briefing.md b/kis_trader/backtest/results/optuna_breakout_tpe_20260904_152752.briefing.md new file mode 100644 index 0000000..66a6257 --- /dev/null +++ b/kis_trader/backtest/results/optuna_breakout_tpe_20260904_152752.briefing.md @@ -0,0 +1,49 @@ +# Optuna ๋ธŒ๋ฆฌํ•‘ โ€” ๋ŒํŒŒ (tpe) +๊ธฐ๊ฐ„: 2026-08-31 ~ 2026-09-04 (๊ฑฐ๋ž˜์ผโ‰ˆ5์ผ) ยท trials 200/200 +ํƒ์ƒ‰ ๊ฒŒ์ดํŠธ: WRโ‰ฅ0% PFโ‰ฅ0 ยท min_tradesโ‰ฅ10 | ํ›„๋ณด ๊ฒŒ์ดํŠธ: WRโ‰ฅ40% PFโ‰ฅ1 ยท min_tradesโ‰ฅ10 +- min_trades=10: **ํ•ฉ๊ฒฉ ์ธ์ • ์ตœ์†Œ ๊ฑฐ๋ž˜ ๊ฑด์ˆ˜**(ํ‘œ๋ณธ ๋ถ€์กฑยท์šฐ์—ฐ ์Šน๋ฅ  ๋ฐฉ์ง€). ์ด๋ณด๋‹ค ์ ์€ ์กฐํ•ฉ์€ ํ•™์Šต/ํ›„๋ณด ์ง‘๊ณ„์—์„œ ์ œ์™ธ๋ฉ๋‹ˆ๋‹ค. +ํ•™์Šต์šฉ ํ†ต๊ณผ 0๊ฑด ยท ์‚ฌํ›„ํ•ฉ๊ฒฉ(results_gated) 0๊ฑด + +## ๊ณผ์ ํ•ฉยท์ ์šฉ ๊ฐ€๋Šฅ๋„ (ํœด๋ฆฌ์Šคํ‹ฑ) +- **๊ณผ์ ํ•ฉ ์œ„ํ—˜ 33.0%** ยท **์ ์šฉ ๊ฐ€๋Šฅ๋„ 67.0%** ยท ํŒ์ •: **์ƒ๋Œ€์ ์œผ๋กœ๋‚ฎ์Œ** โ€” ํœด๋ฆฌ์Šคํ‹ฑ์ƒ ์œ„ํ—˜ ์ƒ๋Œ€์  ๋‚ฎ์Œ โ€” ๊ทธ๋ž˜๋„ ๋‹ค์ผ ํ™•์ธ ๊ถŒ์žฅ + - ํ‘œ๋ณธ ์žฅ์ผ: +0.0p โ€” ๊ฑฐ๋ž˜์ผโ‰ˆ5์ผ โ€” ํ‘œ๋ณธ ์ผ์ˆ˜ ์ƒ๋Œ€์  ์–‘ํ˜ธ + - ๊ฑฐ๋ž˜ ํ‘œ๋ณธ: +25.0p โ€” ํ†ต๊ณผ ํ›„๋ณด ์—†์Œ โ€” ์ ์šฉ ๋ถˆ๊ฐ€ + - ์Šน๋ฅ ยทPF ์ด์ƒ์น˜: +0.0p โ€” ์ด์ƒ์น˜ ์—†์Œ + - ๊ฒŒ์ดํŠธ ์ปค๋ฒ„: +8.0p โ€” ํ•™์Šตยทgated ๋ชจ๋‘ ๋น„์–ด ์žˆ์Œ + - PnL ๊ณ ์›: +0.0p โ€” ๊ณ ์› ํŒ์ • ์Šคํ‚ต +- _์ฐธ๊ณ : ๊ณผ์ ํ•ฉ%๋Š” ๊ต์ฐจ๊ฒ€์ฆ ์ ์ˆ˜๊ฐ€ ์•„๋‹ˆ๋ผ ํ‘œ๋ณธยท์ด์ƒ์น˜ยท๊ณ ์› ํœด๋ฆฌ์Šคํ‹ฑ์ž…๋‹ˆ๋‹ค. ์ ์šฉ ๊ฐ€๋Šฅ๋„%=100โˆ’๊ณผ์ ํ•ฉ์œ„ํ—˜%. DB ์ ์šฉ ๋ฒ„ํŠผ ํ™œ์„ฑ ์กฐ๊ฑด(gated PnL>0)๊ณผ๋Š” ๋ณ„๊ฐœ์ž…๋‹ˆ๋‹ค._ + +## ์ตœ์ข… ์„ ํƒ ํ›„๋ณด (๊ทœ์น™ ยท DB ์ ์šฉ ์ „ ํ™•์ธ) +- ์•„๋ž˜๋Š” **์—ญํ• ์ด ๋‹ค๋ฅธ** 4์ข… ํ›„๋ณด์ž…๋‹ˆ๋‹ค. mode Top10 1์œ„ โ‰  ์ต์ ˆ ๋Œ€ํ‘œ ยท **DB 1์ˆœ์œ„๋Š” ์‚ฌํ›„ํ•ฉ๊ฒฉ(gated)** ์ž…๋‹ˆ๋‹ค. +- mode pool: `positive` ยท scoring: `band_proximity_p25_p75` + +### ํ›„๋ณด 4์ข… +- **โ‘  ์‚ฌํ›„ํ•ฉ๊ฒฉ 1์œ„ (apply: gated)**: ์—†์Œ +- **โ‘ก ์•ˆ์ • 1์œ„ (apply: stable)**: ์—†์Œ +- **โ‘ข mode_combo (apply: mode)**: ์—†์Œ (๋ฏธ์‚ฐ์ถœยท๊ตฌ JSON) +- **โ‘ฃ mode Top10 1์œ„ (apply: consensus ยท ๋ฐด๋“œ ์ „ํ˜• trial)**: ์—†์Œ +- mode Top10 meta: pool 0๊ฑด ยท ์ถ• 0๊ฐœ + +### ์ถ”์ฒœ (์ž๋™ ยท confirm ํ•„์ˆ˜) +1. **์‚ฌํ›„ํ•ฉ๊ฒฉ 0๊ฑด โ†’ DB ์ ์šฉ ๋น„๊ถŒ์žฅ.** ํ˜„ํ–‰ DB ์œ ์ง€ + ์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑยท๊ธฐ๊ฐ„ ์žฌ๊ฒ€์ฆ. +- โš  ์•ˆ์ • ๊ฒŒ์ดํŠธ 0๊ฑด โ†’ ์•ˆ์ • Top์€ **์ ์ˆ˜์ˆœ ํด๋ฐฑ** (์•ˆ์ • ๊ฒŒ์ดํŠธ 0๊ฑด โ†’ ํ•™์Šตํ’€ ์•ˆ์ •์ ์ˆ˜์ˆœ TopN (๋งˆ์ด๋„ˆ์Šค PnL ํฌํ•จ ยท ์ƒ๋Œ€๋น„๊ต)) + +## ์ด์ „ ์žฅ์—์„œ๋Š” +- ์‹ค๋งค ๋™๊ธฐ๊ฐ„ ์ฒญ์‚ฐ 30๊ฑด ยท ์Šน๋ฅ  27% ยท ํ•ฉ์‚ฐ PnL -82,108์› (๋ฐฑํ…Œ Optuna์™€ ์ˆซ์ž ๋‹ฌ๋ผ๋„ ์ •์ƒ โ€” ๊ณ ์ŠคํŠธยท์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑ ๊ฒฝ๋กœ ์ฐจ์ด). +- ์ด ๊ธฐ๊ฐ„ ๋ฐฑํ…Œ์—์„œ๋Š” **์œ ์˜๋ฏธํ•œ ํ†ต๊ณผ ์กฐํ•ฉ์ด ๊ฑฐ์˜ ์—†์—ˆ์Šต๋‹ˆ๋‹ค.** ์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑยท์†์ ˆยท์‹œ๊ฐ„์ฐฝ์„ ๋จผ์ € ์ ๊ฒ€ํ•˜์„ธ์š” (๋ŒํŒŒ 0๊ฑด์ด๋ฉด ํŠนํžˆ). + +## ์•ž์œผ๋กœ ์žฅ์—์„œ๋Š” +- **1~2์ผ Optuna best๋ฅผ ๋ฐ”๋กœ ์‹ค๋งค์— ๋„ฃ์ง€ ๋งˆ์„ธ์š”.** ๋‹ค์ผ(โ‰ฅ5๊ฑฐ๋ž˜์ผ) ์žฌ๊ฒ€์ฆยท์›น๋ฐฑํ…Œ 1ํšŒ ํ›„ ๊ฒ€ํ† . +- ์ ์šฉ ์‹œ์—๋Š” `results_gated` ํ›„๋ณด๋งŒ. ํƒ์ƒ‰์šฉ best(objective)์™€ ๋‹ค๋ฅผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. +- ์žฅ์ด ์ข์•„์ง€๊ฑฐ๋‚˜ ๋ณ€๋™์„ฑ์ด ์ปค์ง€๋ฉด: ์†์ ˆยทํŠธ๋ ˆ์ผยท์‹œ๊ฐ„์ฐฝ์ด ๋จผ์ € ๊นจ์ง‘๋‹ˆ๋‹ค. ์Šน๋ฅ  ์ž๋ž‘๋ณด๋‹ค **์†์ ˆ์ด ์‚ด์•„ ์žˆ๋Š”์ง€**๋ฅผ ๋ณด์„ธ์š”. +- ํ˜„์žฌ ์‚ฌํ›„ํ•ฉ๊ฒฉ 0๊ฑด โ†’ ํŒŒ๋ผ๋ฏธํ„ฐ ์œ ์ง€(ํ˜„ํ–‰ DB) + ์œ ๋‹ˆ๋ฒ„์Šค/๋ฐ์ดํ„ฐ ์ ๊ฒ€์ด ์šฐ์„ ์ž…๋‹ˆ๋‹ค. + +_์ƒ์„ฑ: 2026-09-04 15:27:52 (rule)_ + +## AI ์ฝ”๋ฉ˜ํŠธ (์ด์ „ ์žฅ / ์•ž์œผ๋กœ ์žฅ) [gemini] + +**์ด์ „ ์žฅ์—์„œ๋Š”** +์ด๋ฒˆ 5๊ฑฐ๋ž˜์ผ ๋ฐฑํ…Œ์ŠคํŠธ์—์„œ Optuna๋Š” **์‚ฌํ›„ํ•ฉ๊ฒฉ/ํ•™์Šต์šฉ ํ†ต๊ณผ ์กฐํ•ฉ์„ ์ „ํ˜€ ์ฐพ์ง€ ๋ชปํ–ˆ์Šต๋‹ˆ๋‹ค.** ์ด๋Š” ์ตœ์†Œ ๊ฑฐ๋ž˜ ๊ฑด์ˆ˜(10๊ฑด) ๋ฏธ์ถฉ์กฑ์œผ๋กœ **ํ‘œ๋ณธ ๋ถ€์กฑ ๋ฐ ์šฐ์—ฐ ์Šน๋ฅ  ๊ฐ€๋Šฅ์„ฑ**์„ ๊ฒฝ๊ณ ํ•ฉ๋‹ˆ๋‹ค. **๊ณผ์ ํ•ฉ ์œ„ํ—˜๋„ 33%**๋กœ ๋‚ฎ์ง€ ์•Š์œผ๋ฉฐ, ์‹ค์ œ ๋งค๋งค์™€ ๋ฐฑํ…Œ์ŠคํŠธ ๊ฐ„ **๊ดด๋ฆฌ(๊ณ ์ŠคํŠธํผ์ง€ ๋“ฑ)๊ฐ€ ์‹ฌํ•  ์ˆ˜ ์žˆ์Œ**์„ ๋ช…์‹ฌํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. + +**์•ž์œผ๋กœ ์žฅ์—์„œ๋Š”** +**์‚ฌํ›„ํ•ฉ๊ฒฉ 0๊ฑด์ด๋ฏ€๋กœ DB ์ ์šฉ์€ ๋น„๊ถŒ์žฅ**๋ฉ๋‹ˆ๋‹ค. `mode Top10 1์œ„`๋ฅผ ์ต์ ˆ ๋Œ€ํ‘œ๋กœ ๋‹จ์ • ๋งˆ์„ธ์š”. **DB 1์ˆœ์œ„๋Š” ํ•ญ์ƒ ์‚ฌํ›„ํ•ฉ๊ฒฉ(gated) ์ „๋žต**์ž…๋‹ˆ๋‹ค. ํ˜„์žฌ๋Š” ๊ธฐ์กด ํŒŒ๋ผ๋ฏธํ„ฐ ์œ ์ง€์™€ ํ•จ๊ป˜ ์œ ๋‹ˆ๋ฒ„์Šค, ํ‹ฑ, ๊ธฐ๊ฐ„ ๋“ฑ **๋ฐ์ดํ„ฐ ์žฌ๊ฒ€์ฆ์ด ์šฐ์„ **์ž…๋‹ˆ๋‹ค. **ํŠน์ • ์ข…๋ชฉ ๋งค์ˆ˜ ์ถ”์ฒœยทํ™•์ • ์ˆ˜์ต ์•ฝ์†์€ ๋ถˆ๊ฐ€**ํ•˜๋ฉฐ, ๋ฐ˜๋“œ์‹œ **๋‹ค์ผ(โ‰ฅ5๊ฑฐ๋ž˜์ผ) ์žฌ๊ฒ€์ฆ** ํ›„ ์‹ ์ค‘ํžˆ ์ ‘๊ทผํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. diff --git a/kis_trader/backtest/results/optuna_breakout_tpe_20260904_153803.briefing.md b/kis_trader/backtest/results/optuna_breakout_tpe_20260904_153803.briefing.md new file mode 100644 index 0000000..9a83287 --- /dev/null +++ b/kis_trader/backtest/results/optuna_breakout_tpe_20260904_153803.briefing.md @@ -0,0 +1,49 @@ +# Optuna ๋ธŒ๋ฆฌํ•‘ โ€” ๋ŒํŒŒ (tpe) +๊ธฐ๊ฐ„: 2026-08-31 ~ 2026-09-04 (๊ฑฐ๋ž˜์ผโ‰ˆ5์ผ) ยท trials 200/200 +ํƒ์ƒ‰ ๊ฒŒ์ดํŠธ: WRโ‰ฅ0% PFโ‰ฅ0 ยท min_tradesโ‰ฅ10 | ํ›„๋ณด ๊ฒŒ์ดํŠธ: WRโ‰ฅ40% PFโ‰ฅ1 ยท min_tradesโ‰ฅ10 +- min_trades=10: **ํ•ฉ๊ฒฉ ์ธ์ • ์ตœ์†Œ ๊ฑฐ๋ž˜ ๊ฑด์ˆ˜**(ํ‘œ๋ณธ ๋ถ€์กฑยท์šฐ์—ฐ ์Šน๋ฅ  ๋ฐฉ์ง€). ์ด๋ณด๋‹ค ์ ์€ ์กฐํ•ฉ์€ ํ•™์Šต/ํ›„๋ณด ์ง‘๊ณ„์—์„œ ์ œ์™ธ๋ฉ๋‹ˆ๋‹ค. +ํ•™์Šต์šฉ ํ†ต๊ณผ 0๊ฑด ยท ์‚ฌํ›„ํ•ฉ๊ฒฉ(results_gated) 0๊ฑด + +## ๊ณผ์ ํ•ฉยท์ ์šฉ ๊ฐ€๋Šฅ๋„ (ํœด๋ฆฌ์Šคํ‹ฑ) +- **๊ณผ์ ํ•ฉ ์œ„ํ—˜ 33.0%** ยท **์ ์šฉ ๊ฐ€๋Šฅ๋„ 67.0%** ยท ํŒ์ •: **์ƒ๋Œ€์ ์œผ๋กœ๋‚ฎ์Œ** โ€” ํœด๋ฆฌ์Šคํ‹ฑ์ƒ ์œ„ํ—˜ ์ƒ๋Œ€์  ๋‚ฎ์Œ โ€” ๊ทธ๋ž˜๋„ ๋‹ค์ผ ํ™•์ธ ๊ถŒ์žฅ + - ํ‘œ๋ณธ ์žฅ์ผ: +0.0p โ€” ๊ฑฐ๋ž˜์ผโ‰ˆ5์ผ โ€” ํ‘œ๋ณธ ์ผ์ˆ˜ ์ƒ๋Œ€์  ์–‘ํ˜ธ + - ๊ฑฐ๋ž˜ ํ‘œ๋ณธ: +25.0p โ€” ํ†ต๊ณผ ํ›„๋ณด ์—†์Œ โ€” ์ ์šฉ ๋ถˆ๊ฐ€ + - ์Šน๋ฅ ยทPF ์ด์ƒ์น˜: +0.0p โ€” ์ด์ƒ์น˜ ์—†์Œ + - ๊ฒŒ์ดํŠธ ์ปค๋ฒ„: +8.0p โ€” ํ•™์Šตยทgated ๋ชจ๋‘ ๋น„์–ด ์žˆ์Œ + - PnL ๊ณ ์›: +0.0p โ€” ๊ณ ์› ํŒ์ • ์Šคํ‚ต +- _์ฐธ๊ณ : ๊ณผ์ ํ•ฉ%๋Š” ๊ต์ฐจ๊ฒ€์ฆ ์ ์ˆ˜๊ฐ€ ์•„๋‹ˆ๋ผ ํ‘œ๋ณธยท์ด์ƒ์น˜ยท๊ณ ์› ํœด๋ฆฌ์Šคํ‹ฑ์ž…๋‹ˆ๋‹ค. ์ ์šฉ ๊ฐ€๋Šฅ๋„%=100โˆ’๊ณผ์ ํ•ฉ์œ„ํ—˜%. DB ์ ์šฉ ๋ฒ„ํŠผ ํ™œ์„ฑ ์กฐ๊ฑด(gated PnL>0)๊ณผ๋Š” ๋ณ„๊ฐœ์ž…๋‹ˆ๋‹ค._ + +## ์ตœ์ข… ์„ ํƒ ํ›„๋ณด (๊ทœ์น™ ยท DB ์ ์šฉ ์ „ ํ™•์ธ) +- ์•„๋ž˜๋Š” **์—ญํ• ์ด ๋‹ค๋ฅธ** 4์ข… ํ›„๋ณด์ž…๋‹ˆ๋‹ค. mode Top10 1์œ„ โ‰  ์ต์ ˆ ๋Œ€ํ‘œ ยท **DB 1์ˆœ์œ„๋Š” ์‚ฌํ›„ํ•ฉ๊ฒฉ(gated)** ์ž…๋‹ˆ๋‹ค. +- mode pool: `positive` ยท scoring: `band_proximity_p25_p75` + +### ํ›„๋ณด 4์ข… +- **โ‘  ์‚ฌํ›„ํ•ฉ๊ฒฉ 1์œ„ (apply: gated)**: ์—†์Œ +- **โ‘ก ์•ˆ์ • 1์œ„ (apply: stable)**: ์—†์Œ +- **โ‘ข mode_combo (apply: mode)**: ์—†์Œ (๋ฏธ์‚ฐ์ถœยท๊ตฌ JSON) +- **โ‘ฃ mode Top10 1์œ„ (apply: consensus ยท ๋ฐด๋“œ ์ „ํ˜• trial)**: ์—†์Œ +- mode Top10 meta: pool 0๊ฑด ยท ์ถ• 0๊ฐœ + +### ์ถ”์ฒœ (์ž๋™ ยท confirm ํ•„์ˆ˜) +1. **์‚ฌํ›„ํ•ฉ๊ฒฉ 0๊ฑด โ†’ DB ์ ์šฉ ๋น„๊ถŒ์žฅ.** ํ˜„ํ–‰ DB ์œ ์ง€ + ์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑยท๊ธฐ๊ฐ„ ์žฌ๊ฒ€์ฆ. +- โš  ์•ˆ์ • ๊ฒŒ์ดํŠธ 0๊ฑด โ†’ ์•ˆ์ • Top์€ **์ ์ˆ˜์ˆœ ํด๋ฐฑ** (์•ˆ์ • ๊ฒŒ์ดํŠธ 0๊ฑด โ†’ ํ•™์Šตํ’€ ์•ˆ์ •์ ์ˆ˜์ˆœ TopN (๋งˆ์ด๋„ˆ์Šค PnL ํฌํ•จ ยท ์ƒ๋Œ€๋น„๊ต)) + +## ์ด์ „ ์žฅ์—์„œ๋Š” +- ์‹ค๋งค ๋™๊ธฐ๊ฐ„ ์ฒญ์‚ฐ 30๊ฑด ยท ์Šน๋ฅ  27% ยท ํ•ฉ์‚ฐ PnL -82,108์› (๋ฐฑํ…Œ Optuna์™€ ์ˆซ์ž ๋‹ฌ๋ผ๋„ ์ •์ƒ โ€” ๊ณ ์ŠคํŠธยท์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑ ๊ฒฝ๋กœ ์ฐจ์ด). +- ์ด ๊ธฐ๊ฐ„ ๋ฐฑํ…Œ์—์„œ๋Š” **์œ ์˜๋ฏธํ•œ ํ†ต๊ณผ ์กฐํ•ฉ์ด ๊ฑฐ์˜ ์—†์—ˆ์Šต๋‹ˆ๋‹ค.** ์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑยท์†์ ˆยท์‹œ๊ฐ„์ฐฝ์„ ๋จผ์ € ์ ๊ฒ€ํ•˜์„ธ์š” (๋ŒํŒŒ 0๊ฑด์ด๋ฉด ํŠนํžˆ). + +## ์•ž์œผ๋กœ ์žฅ์—์„œ๋Š” +- **1~2์ผ Optuna best๋ฅผ ๋ฐ”๋กœ ์‹ค๋งค์— ๋„ฃ์ง€ ๋งˆ์„ธ์š”.** ๋‹ค์ผ(โ‰ฅ5๊ฑฐ๋ž˜์ผ) ์žฌ๊ฒ€์ฆยท์›น๋ฐฑํ…Œ 1ํšŒ ํ›„ ๊ฒ€ํ† . +- ์ ์šฉ ์‹œ์—๋Š” `results_gated` ํ›„๋ณด๋งŒ. ํƒ์ƒ‰์šฉ best(objective)์™€ ๋‹ค๋ฅผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. +- ์žฅ์ด ์ข์•„์ง€๊ฑฐ๋‚˜ ๋ณ€๋™์„ฑ์ด ์ปค์ง€๋ฉด: ์†์ ˆยทํŠธ๋ ˆ์ผยท์‹œ๊ฐ„์ฐฝ์ด ๋จผ์ € ๊นจ์ง‘๋‹ˆ๋‹ค. ์Šน๋ฅ  ์ž๋ž‘๋ณด๋‹ค **์†์ ˆ์ด ์‚ด์•„ ์žˆ๋Š”์ง€**๋ฅผ ๋ณด์„ธ์š”. +- ํ˜„์žฌ ์‚ฌํ›„ํ•ฉ๊ฒฉ 0๊ฑด โ†’ ํŒŒ๋ผ๋ฏธํ„ฐ ์œ ์ง€(ํ˜„ํ–‰ DB) + ์œ ๋‹ˆ๋ฒ„์Šค/๋ฐ์ดํ„ฐ ์ ๊ฒ€์ด ์šฐ์„ ์ž…๋‹ˆ๋‹ค. + +_์ƒ์„ฑ: 2026-09-04 15:38:03 (rule)_ + +## AI ์ฝ”๋ฉ˜ํŠธ (์ด์ „ ์žฅ / ์•ž์œผ๋กœ ์žฅ) [gemini] + +**์ด์ „ ์žฅ์—์„œ๋Š”** +์ง€๋‚œ 5๊ฑฐ๋ž˜์ผ ์‹ค๋งค๋Š” ์Šน๋ฅ  27%์— -8๋งŒ ์› ์†์‹ค์„ ๊ธฐ๋กํ–ˆ์Šต๋‹ˆ๋‹ค. ๋ฐฑํ…Œ์ŠคํŠธ ๊ฒฐ๊ณผ๋Š” ๋” ๊ฒฝ๊ณ ์ ์ž…๋‹ˆ๋‹ค. `min_trades=10` ๊ธฐ์ค€์„ ํ†ต๊ณผํ•œ ์œ ํšจํ•œ ์กฐํ•ฉ์ด ์ „ํ˜€ ์—†์—ˆ๊ณ , ์‚ฌํ›„ํ•ฉ๊ฒฉ ์กฐํ•ฉ ๋˜ํ•œ 0๊ฑด์ž…๋‹ˆ๋‹ค. ์ด๋Š” ํ•ด๋‹น ๊ธฐ๊ฐ„ ์šฐ๋ฆฌ ์ „๋žต์ด ์‹œ์žฅ ํŠน์„ฑ์— ๋งž์ง€ ์•Š์•˜์Œ์„ ๋ณด์—ฌ์ฃผ๋ฉฐ, ๋ฐฑํ…Œ์ŠคํŠธ์™€ ์‹ค๋งค ๊ฐ„ ๊ดด๋ฆฌ(๊ณ ์ŠคํŠธ ์Šฌ๋ฆฌํ”ผ์ง€ ๋“ฑ)๊ฐ€ ์žˆ์„ ์ˆ˜ ์žˆ์œผ๋‹ˆ ์œ ๋‹ˆ๋ฒ„์Šค, ํ‹ฑ ๋‹จ์œ„ ๋“ฑ ๊ธฐ๋ณธ ์„ค์ • ์ ๊ฒ€์ด ์‹œ๊ธ‰ํ•ฉ๋‹ˆ๋‹ค. + +**์•ž์œผ๋กœ ์žฅ์—์„œ๋Š”** +๋ชจ๋“  ํ›„๋ณด ์กฐํ•ฉ์ด '์—†์Œ'์ธ ์ ์€ ๊ณผ์ ํ•ฉ ๋ฐ ํ‘œ๋ณธ ๋ถ€์กฑ ์œ„ํ—˜์„ ๊ฐ•ํ•˜๊ฒŒ ๊ฒฝ๊ณ ํ•ฉ๋‹ˆ๋‹ค. Optuna์—์„œ ํƒ์ƒ‰๋œ ๋‹จ๊ธฐ best๋Š” ์ ˆ๋Œ€ ๋ฐ”๋กœ ์‹ค๋งค์— ์ ์šฉํ•ด์„  ์•ˆ ๋ฉ๋‹ˆ๋‹ค. mode Top10 1์œ„๋„ ์ต์ ˆ ๋Œ€ํ‘œ๊ฐ€ ์•„๋‹Œ ๋งŒํผ, ์˜ค์ง `์‚ฌํ›„ํ•ฉ๊ฒฉ(gated)`๋œ ํ›„๋ณด๋งŒ ์‹ค๋งค ์ ์šฉ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค. ํ˜„์žฌ๋Š” 0๊ฑด์ด๋ฏ€๋กœ, **ํ˜„ํ–‰ DB๋ฅผ ์œ ์ง€ํ•˜๋ฉฐ ์œ ๋‹ˆ๋ฒ„์ŠคยทํŒŒ๋ผ๋ฏธํ„ฐ ์žฌ๊ฒ€์ฆ์ด ์šฐ์„ ์ž…๋‹ˆ๋‹ค.** ์งง์€ ๊ธฐ๊ฐ„๊ณผ ์œ ํšจ ์ƒ˜ํ”Œ ๋ถ€์กฑ์œผ๋กœ ๋ฐฑํ…Œ์ŠคํŠธ ๊ฒฐ๊ณผ ์ž์ฒด์— ๋Œ€ํ•œ ์‹ ๋ขฐ๋„๊ฐ€ ๋งค์šฐ ๋‚ฎ์Œ์„ ๋ช…์‹ฌํ•˜์„ธ์š”. diff --git a/kis_trader/backtest/results/optuna_breakout_tpe_20260904_154640.briefing.md b/kis_trader/backtest/results/optuna_breakout_tpe_20260904_154640.briefing.md new file mode 100644 index 0000000..7bb4ebe --- /dev/null +++ b/kis_trader/backtest/results/optuna_breakout_tpe_20260904_154640.briefing.md @@ -0,0 +1,49 @@ +# Optuna ๋ธŒ๋ฆฌํ•‘ โ€” ๋ŒํŒŒ (tpe) +๊ธฐ๊ฐ„: 2026-08-31 ~ 2026-09-04 (๊ฑฐ๋ž˜์ผโ‰ˆ5์ผ) ยท trials 200/200 +ํƒ์ƒ‰ ๊ฒŒ์ดํŠธ: WRโ‰ฅ0% PFโ‰ฅ0 ยท min_tradesโ‰ฅ10 | ํ›„๋ณด ๊ฒŒ์ดํŠธ: WRโ‰ฅ40% PFโ‰ฅ1 ยท min_tradesโ‰ฅ10 +- min_trades=10: **ํ•ฉ๊ฒฉ ์ธ์ • ์ตœ์†Œ ๊ฑฐ๋ž˜ ๊ฑด์ˆ˜**(ํ‘œ๋ณธ ๋ถ€์กฑยท์šฐ์—ฐ ์Šน๋ฅ  ๋ฐฉ์ง€). ์ด๋ณด๋‹ค ์ ์€ ์กฐํ•ฉ์€ ํ•™์Šต/ํ›„๋ณด ์ง‘๊ณ„์—์„œ ์ œ์™ธ๋ฉ๋‹ˆ๋‹ค. +ํ•™์Šต์šฉ ํ†ต๊ณผ 0๊ฑด ยท ์‚ฌํ›„ํ•ฉ๊ฒฉ(results_gated) 0๊ฑด + +## ๊ณผ์ ํ•ฉยท์ ์šฉ ๊ฐ€๋Šฅ๋„ (ํœด๋ฆฌ์Šคํ‹ฑ) +- **๊ณผ์ ํ•ฉ ์œ„ํ—˜ 33.0%** ยท **์ ์šฉ ๊ฐ€๋Šฅ๋„ 67.0%** ยท ํŒ์ •: **์ƒ๋Œ€์ ์œผ๋กœ๋‚ฎ์Œ** โ€” ํœด๋ฆฌ์Šคํ‹ฑ์ƒ ์œ„ํ—˜ ์ƒ๋Œ€์  ๋‚ฎ์Œ โ€” ๊ทธ๋ž˜๋„ ๋‹ค์ผ ํ™•์ธ ๊ถŒ์žฅ + - ํ‘œ๋ณธ ์žฅ์ผ: +0.0p โ€” ๊ฑฐ๋ž˜์ผโ‰ˆ5์ผ โ€” ํ‘œ๋ณธ ์ผ์ˆ˜ ์ƒ๋Œ€์  ์–‘ํ˜ธ + - ๊ฑฐ๋ž˜ ํ‘œ๋ณธ: +25.0p โ€” ํ†ต๊ณผ ํ›„๋ณด ์—†์Œ โ€” ์ ์šฉ ๋ถˆ๊ฐ€ + - ์Šน๋ฅ ยทPF ์ด์ƒ์น˜: +0.0p โ€” ์ด์ƒ์น˜ ์—†์Œ + - ๊ฒŒ์ดํŠธ ์ปค๋ฒ„: +8.0p โ€” ํ•™์Šตยทgated ๋ชจ๋‘ ๋น„์–ด ์žˆ์Œ + - PnL ๊ณ ์›: +0.0p โ€” ๊ณ ์› ํŒ์ • ์Šคํ‚ต +- _์ฐธ๊ณ : ๊ณผ์ ํ•ฉ%๋Š” ๊ต์ฐจ๊ฒ€์ฆ ์ ์ˆ˜๊ฐ€ ์•„๋‹ˆ๋ผ ํ‘œ๋ณธยท์ด์ƒ์น˜ยท๊ณ ์› ํœด๋ฆฌ์Šคํ‹ฑ์ž…๋‹ˆ๋‹ค. ์ ์šฉ ๊ฐ€๋Šฅ๋„%=100โˆ’๊ณผ์ ํ•ฉ์œ„ํ—˜%. DB ์ ์šฉ ๋ฒ„ํŠผ ํ™œ์„ฑ ์กฐ๊ฑด(gated PnL>0)๊ณผ๋Š” ๋ณ„๊ฐœ์ž…๋‹ˆ๋‹ค._ + +## ์ตœ์ข… ์„ ํƒ ํ›„๋ณด (๊ทœ์น™ ยท DB ์ ์šฉ ์ „ ํ™•์ธ) +- ์•„๋ž˜๋Š” **์—ญํ• ์ด ๋‹ค๋ฅธ** 4์ข… ํ›„๋ณด์ž…๋‹ˆ๋‹ค. mode Top10 1์œ„ โ‰  ์ต์ ˆ ๋Œ€ํ‘œ ยท **DB 1์ˆœ์œ„๋Š” ์‚ฌํ›„ํ•ฉ๊ฒฉ(gated)** ์ž…๋‹ˆ๋‹ค. +- mode pool: `positive` ยท scoring: `band_proximity_p25_p75` + +### ํ›„๋ณด 4์ข… +- **โ‘  ์‚ฌํ›„ํ•ฉ๊ฒฉ 1์œ„ (apply: gated)**: ์—†์Œ +- **โ‘ก ์•ˆ์ • 1์œ„ (apply: stable)**: ์—†์Œ +- **โ‘ข mode_combo (apply: mode)**: ์—†์Œ (๋ฏธ์‚ฐ์ถœยท๊ตฌ JSON) +- **โ‘ฃ mode Top10 1์œ„ (apply: consensus ยท ๋ฐด๋“œ ์ „ํ˜• trial)**: ์—†์Œ +- mode Top10 meta: pool 0๊ฑด ยท ์ถ• 0๊ฐœ + +### ์ถ”์ฒœ (์ž๋™ ยท confirm ํ•„์ˆ˜) +1. **์‚ฌํ›„ํ•ฉ๊ฒฉ 0๊ฑด โ†’ DB ์ ์šฉ ๋น„๊ถŒ์žฅ.** ํ˜„ํ–‰ DB ์œ ์ง€ + ์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑยท๊ธฐ๊ฐ„ ์žฌ๊ฒ€์ฆ. +- โš  ์•ˆ์ • ๊ฒŒ์ดํŠธ 0๊ฑด โ†’ ์•ˆ์ • Top์€ **์ ์ˆ˜์ˆœ ํด๋ฐฑ** (์•ˆ์ • ๊ฒŒ์ดํŠธ 0๊ฑด โ†’ ํ•™์Šตํ’€ ์•ˆ์ •์ ์ˆ˜์ˆœ TopN (๋งˆ์ด๋„ˆ์Šค PnL ํฌํ•จ ยท ์ƒ๋Œ€๋น„๊ต)) + +## ์ด์ „ ์žฅ์—์„œ๋Š” +- ์‹ค๋งค ๋™๊ธฐ๊ฐ„ ์ฒญ์‚ฐ 30๊ฑด ยท ์Šน๋ฅ  27% ยท ํ•ฉ์‚ฐ PnL -82,108์› (๋ฐฑํ…Œ Optuna์™€ ์ˆซ์ž ๋‹ฌ๋ผ๋„ ์ •์ƒ โ€” ๊ณ ์ŠคํŠธยท์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑ ๊ฒฝ๋กœ ์ฐจ์ด). +- ์ด ๊ธฐ๊ฐ„ ๋ฐฑํ…Œ์—์„œ๋Š” **์œ ์˜๋ฏธํ•œ ํ†ต๊ณผ ์กฐํ•ฉ์ด ๊ฑฐ์˜ ์—†์—ˆ์Šต๋‹ˆ๋‹ค.** ์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑยท์†์ ˆยท์‹œ๊ฐ„์ฐฝ์„ ๋จผ์ € ์ ๊ฒ€ํ•˜์„ธ์š” (๋ŒํŒŒ 0๊ฑด์ด๋ฉด ํŠนํžˆ). + +## ์•ž์œผ๋กœ ์žฅ์—์„œ๋Š” +- **1~2์ผ Optuna best๋ฅผ ๋ฐ”๋กœ ์‹ค๋งค์— ๋„ฃ์ง€ ๋งˆ์„ธ์š”.** ๋‹ค์ผ(โ‰ฅ5๊ฑฐ๋ž˜์ผ) ์žฌ๊ฒ€์ฆยท์›น๋ฐฑํ…Œ 1ํšŒ ํ›„ ๊ฒ€ํ† . +- ์ ์šฉ ์‹œ์—๋Š” `results_gated` ํ›„๋ณด๋งŒ. ํƒ์ƒ‰์šฉ best(objective)์™€ ๋‹ค๋ฅผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. +- ์žฅ์ด ์ข์•„์ง€๊ฑฐ๋‚˜ ๋ณ€๋™์„ฑ์ด ์ปค์ง€๋ฉด: ์†์ ˆยทํŠธ๋ ˆ์ผยท์‹œ๊ฐ„์ฐฝ์ด ๋จผ์ € ๊นจ์ง‘๋‹ˆ๋‹ค. ์Šน๋ฅ  ์ž๋ž‘๋ณด๋‹ค **์†์ ˆ์ด ์‚ด์•„ ์žˆ๋Š”์ง€**๋ฅผ ๋ณด์„ธ์š”. +- ํ˜„์žฌ ์‚ฌํ›„ํ•ฉ๊ฒฉ 0๊ฑด โ†’ ํŒŒ๋ผ๋ฏธํ„ฐ ์œ ์ง€(ํ˜„ํ–‰ DB) + ์œ ๋‹ˆ๋ฒ„์Šค/๋ฐ์ดํ„ฐ ์ ๊ฒ€์ด ์šฐ์„ ์ž…๋‹ˆ๋‹ค. + +_์ƒ์„ฑ: 2026-09-04 15:46:40 (rule)_ + +## AI ์ฝ”๋ฉ˜ํŠธ (์ด์ „ ์žฅ / ์•ž์œผ๋กœ ์žฅ) [gemini] + +**์ด์ „ ์žฅ์—์„œ๋Š”** +์‹ค๋งค์—์„œ๋Š” PnL -82,108์›(์Šน๋ฅ  27%)์„ ๊ธฐ๋กํ–ˆ๊ณ , ๋ฐฑํ…Œ์ŠคํŠธ ๊ฒฐ๊ณผ๋Š” 0๊ฑด์œผ๋กœ ์œ ์˜๋ฏธํ•œ ํ†ต๊ณผ ์กฐํ•ฉ์ด ์ „๋ฌดํ–ˆ์Šต๋‹ˆ๋‹ค. 5๊ฑฐ๋ž˜์ผ์˜ ๊ทนํžˆ ์งง์€ ๊ธฐ๊ฐ„์€ ๊ณผ์ ํ•ฉ ๋ฐ ํ‘œ๋ณธ ๋ถ€์กฑ ์œ„ํ—˜์ด ๋งค์šฐ ์ปค, ๋ฐฑํ…Œ์ŠคํŠธ์™€ ์‹ค๋งค ๊ฐ„์˜ ํฐ ๊ดด๋ฆฌ(๊ณ ์ŠคํŠธํผ์ง€ ๋“ฑ)๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Œ์„ ๊ฐ•๋ ฅํžˆ ๊ฒฝ๊ณ ํ•ฉ๋‹ˆ๋‹ค. `mode Top10 1์œ„`๋Š” ์ต์ ˆ ๋Œ€ํ‘œ๊ฐ€ ์•„๋‹ˆ๋ฉฐ, DB 1์ˆœ์œ„๋Š” ์‚ฌํ›„ํ•ฉ๊ฒฉ(gated)์ž„์„ ํ•ญ์ƒ ์œ ๋…ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. + +**์•ž์œผ๋กœ ์žฅ์—์„œ๋Š”** +์‚ฌํ›„ํ•ฉ๊ฒฉ(gated) ๊ฒฐ๊ณผ๊ฐ€ 0๊ฑด์ด๋ฏ€๋กœ, ํ˜„ ์‹œ์ ์—์„œ DB ์ ์šฉ์€ ๋น„๊ถŒ์žฅํ•˜๋ฉฐ ๊ธฐ์กด ํŒŒ๋ผ๋ฏธํ„ฐ ๋ฐ ์œ ๋‹ˆ๋ฒ„์Šค/๋ฐ์ดํ„ฐ ์ ๊ฒ€์ด ์šฐ์„ ์ž…๋‹ˆ๋‹ค. ๋‹จ๊ธฐ Optuna ๊ฒฐ๊ณผ๋Š” ์‹ค๋งค ์ ์šฉ ์ „ ๋ฐ˜๋“œ์‹œ ๋‹ค์ผ(โ‰ฅ5๊ฑฐ๋ž˜์ผ) ์žฌ๊ฒ€์ฆ ํ›„ `results_gated` ํ›„๋ณด๋งŒ ์‹ ์ค‘ํžˆ ๊ฒ€ํ† ํ•˜์„ธ์š”. ๋ฐฑํ…Œ์ŠคํŠธ๋Š” ์ด์ƒ์  ํ™˜๊ฒฝ์œผ๋กœ ์‹ค๋งค์™€๋Š” ๋Š˜ ๊ดด๋ฆฌ๋  ์ˆ˜ ์žˆ์Œ์„ ๊ฒฝ๊ณ ํ•˜๋ฉฐ, ํŠน์ • ์ข…๋ชฉ ๋งค์ˆ˜ ์ถ”์ฒœ์ด๋‚˜ ํ™•์ • ์ˆ˜์ต ์•ฝ์†์€ ์ ˆ๋Œ€ ๋ถˆ๊ฐ€ํ•ฉ๋‹ˆ๋‹ค. diff --git a/kis_trader/backtest/results/optuna_breakout_tpe_20260904_155356.briefing.md b/kis_trader/backtest/results/optuna_breakout_tpe_20260904_155356.briefing.md new file mode 100644 index 0000000..ccda101 --- /dev/null +++ b/kis_trader/backtest/results/optuna_breakout_tpe_20260904_155356.briefing.md @@ -0,0 +1,51 @@ +# Optuna ๋ธŒ๋ฆฌํ•‘ โ€” ๋ŒํŒŒ (tpe) +๊ธฐ๊ฐ„: 2026-08-31 ~ 2026-09-04 (๊ฑฐ๋ž˜์ผโ‰ˆ5์ผ) ยท trials 200/200 +ํƒ์ƒ‰ ๊ฒŒ์ดํŠธ: WRโ‰ฅ0% PFโ‰ฅ0 ยท min_tradesโ‰ฅ10 | ํ›„๋ณด ๊ฒŒ์ดํŠธ: WRโ‰ฅ40% PFโ‰ฅ1 ยท min_tradesโ‰ฅ10 +- min_trades=10: **ํ•ฉ๊ฒฉ ์ธ์ • ์ตœ์†Œ ๊ฑฐ๋ž˜ ๊ฑด์ˆ˜**(ํ‘œ๋ณธ ๋ถ€์กฑยท์šฐ์—ฐ ์Šน๋ฅ  ๋ฐฉ์ง€). ์ด๋ณด๋‹ค ์ ์€ ์กฐํ•ฉ์€ ํ•™์Šต/ํ›„๋ณด ์ง‘๊ณ„์—์„œ ์ œ์™ธ๋ฉ๋‹ˆ๋‹ค. +ํ•™์Šต์šฉ ํ†ต๊ณผ 0๊ฑด ยท ์‚ฌํ›„ํ•ฉ๊ฒฉ(results_gated) 0๊ฑด + +## ๊ณผ์ ํ•ฉยท์ ์šฉ ๊ฐ€๋Šฅ๋„ (ํœด๋ฆฌ์Šคํ‹ฑ) +- **๊ณผ์ ํ•ฉ ์œ„ํ—˜ 33.0%** ยท **์ ์šฉ ๊ฐ€๋Šฅ๋„ 67.0%** ยท ํŒ์ •: **์ƒ๋Œ€์ ์œผ๋กœ๋‚ฎ์Œ** โ€” ํœด๋ฆฌ์Šคํ‹ฑ์ƒ ์œ„ํ—˜ ์ƒ๋Œ€์  ๋‚ฎ์Œ โ€” ๊ทธ๋ž˜๋„ ๋‹ค์ผ ํ™•์ธ ๊ถŒ์žฅ + - ํ‘œ๋ณธ ์žฅ์ผ: +0.0p โ€” ๊ฑฐ๋ž˜์ผโ‰ˆ5์ผ โ€” ํ‘œ๋ณธ ์ผ์ˆ˜ ์ƒ๋Œ€์  ์–‘ํ˜ธ + - ๊ฑฐ๋ž˜ ํ‘œ๋ณธ: +25.0p โ€” ํ†ต๊ณผ ํ›„๋ณด ์—†์Œ โ€” ์ ์šฉ ๋ถˆ๊ฐ€ + - ์Šน๋ฅ ยทPF ์ด์ƒ์น˜: +0.0p โ€” ์ด์ƒ์น˜ ์—†์Œ + - ๊ฒŒ์ดํŠธ ์ปค๋ฒ„: +8.0p โ€” ํ•™์Šตยทgated ๋ชจ๋‘ ๋น„์–ด ์žˆ์Œ + - PnL ๊ณ ์›: +0.0p โ€” ๊ณ ์› ํŒ์ • ์Šคํ‚ต +- _์ฐธ๊ณ : ๊ณผ์ ํ•ฉ%๋Š” ๊ต์ฐจ๊ฒ€์ฆ ์ ์ˆ˜๊ฐ€ ์•„๋‹ˆ๋ผ ํ‘œ๋ณธยท์ด์ƒ์น˜ยท๊ณ ์› ํœด๋ฆฌ์Šคํ‹ฑ์ž…๋‹ˆ๋‹ค. ์ ์šฉ ๊ฐ€๋Šฅ๋„%=100โˆ’๊ณผ์ ํ•ฉ์œ„ํ—˜%. DB ์ ์šฉ ๋ฒ„ํŠผ ํ™œ์„ฑ ์กฐ๊ฑด(gated PnL>0)๊ณผ๋Š” ๋ณ„๊ฐœ์ž…๋‹ˆ๋‹ค._ + +## ์ตœ์ข… ์„ ํƒ ํ›„๋ณด (๊ทœ์น™ ยท DB ์ ์šฉ ์ „ ํ™•์ธ) +- ์•„๋ž˜๋Š” **์—ญํ• ์ด ๋‹ค๋ฅธ** 4์ข… ํ›„๋ณด์ž…๋‹ˆ๋‹ค. mode Top10 1์œ„ โ‰  ์ต์ ˆ ๋Œ€ํ‘œ ยท **DB 1์ˆœ์œ„๋Š” ์‚ฌํ›„ํ•ฉ๊ฒฉ(gated)** ์ž…๋‹ˆ๋‹ค. +- mode pool: `positive` ยท scoring: `band_proximity_p25_p75` + +### ํ›„๋ณด 4์ข… +- **โ‘  ์‚ฌํ›„ํ•ฉ๊ฒฉ 1์œ„ (apply: gated)**: ์—†์Œ +- **โ‘ก ์•ˆ์ • 1์œ„ (apply: stable)**: ์—†์Œ +- **โ‘ข mode_combo (apply: mode)**: ์—†์Œ (๋ฏธ์‚ฐ์ถœยท๊ตฌ JSON) +- **โ‘ฃ mode Top10 1์œ„ (apply: consensus ยท ๋ฐด๋“œ ์ „ํ˜• trial)**: ์—†์Œ +- mode Top10 meta: pool 0๊ฑด ยท ์ถ• 0๊ฐœ + +### ์ถ”์ฒœ (์ž๋™ ยท confirm ํ•„์ˆ˜) +1. **์‚ฌํ›„ํ•ฉ๊ฒฉ 0๊ฑด โ†’ DB ์ ์šฉ ๋น„๊ถŒ์žฅ.** ํ˜„ํ–‰ DB ์œ ์ง€ + ์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑยท๊ธฐ๊ฐ„ ์žฌ๊ฒ€์ฆ. +- โš  ์•ˆ์ • ๊ฒŒ์ดํŠธ 0๊ฑด โ†’ ์•ˆ์ • Top์€ **์ ์ˆ˜์ˆœ ํด๋ฐฑ** (์•ˆ์ • ๊ฒŒ์ดํŠธ 0๊ฑด โ†’ ํ•™์Šตํ’€ ์•ˆ์ •์ ์ˆ˜์ˆœ TopN (๋งˆ์ด๋„ˆ์Šค PnL ํฌํ•จ ยท ์ƒ๋Œ€๋น„๊ต)) + +## ์ด์ „ ์žฅ์—์„œ๋Š” +- ์‹ค๋งค ๋™๊ธฐ๊ฐ„ ์ฒญ์‚ฐ 30๊ฑด ยท ์Šน๋ฅ  27% ยท ํ•ฉ์‚ฐ PnL -82,108์› (๋ฐฑํ…Œ Optuna์™€ ์ˆซ์ž ๋‹ฌ๋ผ๋„ ์ •์ƒ โ€” ๊ณ ์ŠคํŠธยท์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑ ๊ฒฝ๋กœ ์ฐจ์ด). +- ์ด ๊ธฐ๊ฐ„ ๋ฐฑํ…Œ์—์„œ๋Š” **์œ ์˜๋ฏธํ•œ ํ†ต๊ณผ ์กฐํ•ฉ์ด ๊ฑฐ์˜ ์—†์—ˆ์Šต๋‹ˆ๋‹ค.** ์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑยท์†์ ˆยท์‹œ๊ฐ„์ฐฝ์„ ๋จผ์ € ์ ๊ฒ€ํ•˜์„ธ์š” (๋ŒํŒŒ 0๊ฑด์ด๋ฉด ํŠนํžˆ). + +## ์•ž์œผ๋กœ ์žฅ์—์„œ๋Š” +- **1~2์ผ Optuna best๋ฅผ ๋ฐ”๋กœ ์‹ค๋งค์— ๋„ฃ์ง€ ๋งˆ์„ธ์š”.** ๋‹ค์ผ(โ‰ฅ5๊ฑฐ๋ž˜์ผ) ์žฌ๊ฒ€์ฆยท์›น๋ฐฑํ…Œ 1ํšŒ ํ›„ ๊ฒ€ํ† . +- ์ ์šฉ ์‹œ์—๋Š” `results_gated` ํ›„๋ณด๋งŒ. ํƒ์ƒ‰์šฉ best(objective)์™€ ๋‹ค๋ฅผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. +- ์žฅ์ด ์ข์•„์ง€๊ฑฐ๋‚˜ ๋ณ€๋™์„ฑ์ด ์ปค์ง€๋ฉด: ์†์ ˆยทํŠธ๋ ˆ์ผยท์‹œ๊ฐ„์ฐฝ์ด ๋จผ์ € ๊นจ์ง‘๋‹ˆ๋‹ค. ์Šน๋ฅ  ์ž๋ž‘๋ณด๋‹ค **์†์ ˆ์ด ์‚ด์•„ ์žˆ๋Š”์ง€**๋ฅผ ๋ณด์„ธ์š”. +- ํ˜„์žฌ ์‚ฌํ›„ํ•ฉ๊ฒฉ 0๊ฑด โ†’ ํŒŒ๋ผ๋ฏธํ„ฐ ์œ ์ง€(ํ˜„ํ–‰ DB) + ์œ ๋‹ˆ๋ฒ„์Šค/๋ฐ์ดํ„ฐ ์ ๊ฒ€์ด ์šฐ์„ ์ž…๋‹ˆ๋‹ค. + +_์ƒ์„ฑ: 2026-09-04 15:53:56 (rule)_ + +## AI ์ฝ”๋ฉ˜ํŠธ (์ด์ „ ์žฅ / ์•ž์œผ๋กœ ์žฅ) [gemini] + +## ์ด์ „ ์žฅ์—์„œ๋Š” + +์ง€๋‚œ 5๊ฑฐ๋ž˜์ผ(8/31~9/4) ๋ฐฑํ…Œ์ŠคํŠธ ๊ฒฐ๊ณผ, ์œ ์˜๋ฏธํ•œ ํ†ต๊ณผ ์กฐํ•ฉ์ด 0๊ฑด์ด์—ˆ์Šต๋‹ˆ๋‹ค. ๋™๊ธฐ๊ฐ„ ์‹ค๋งค๋Š” 30๊ฑด ์ฒญ์‚ฐ, ์Šน๋ฅ  27%, PnL -82,108์›์œผ๋กœ, ๋ฐฑํ…Œ์™€ ์‹ค๋งค ๊ฐ„ ๊ดด๋ฆฌ๊ฐ€ ์ปธ์Šต๋‹ˆ๋‹ค. ์ด๋Š” ๊ณ ์ŠคํŠธํผ์ง€, ์œ ๋‹ˆ๋ฒ„์Šค, ํ‹ฑ ๋ฐ์ดํ„ฐ ๋“ฑ ๋ฐฑํ…Œ-์‹ค๋งค ๊ฒฝ๋กœ ์ฐจ์ด ํƒ“์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์œ ์˜๋ฏธํ•œ ํ†ต๊ณผ ์กฐํ•ฉ ๋ถ€์žฌ๋Š” ์ „๋žต ์ „๋ฐ˜์˜ ์ ๊ฒ€์ด ํ•„์š”ํ•จ์„ ์•Œ๋ฆฝ๋‹ˆ๋‹ค. + +## ์•ž์œผ๋กœ ์žฅ์—์„œ๋Š” + +๊ณผ์ ํ•ฉ, ํ‘œ๋ณธ ๋ถ€์กฑ ์œ„ํ—˜์ด ๋†’์œผ๋‹ˆ, 1~2์ผ Optuna ๊ฒฐ๊ณผ๋ฅผ ๋ฐ”๋กœ ์‹ค๋งค ์ ์šฉ ๋งˆ์‹ญ์‹œ์˜ค. ์ตœ์†Œ 5๊ฑฐ๋ž˜์ผ ์ด์ƒ ๋‹ค์ผ ๊ฒ€์ฆ๊ณผ ์›น๋ฐฑํ…Œ์ŠคํŠธ๊ฐ€ ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค. `results_gated` ํ›„๋ณด๋งŒ ์‹ ์ค‘ํžˆ ๊ณ ๋ คํ•˜๊ณ , 'mode Top10 1์œ„'๋ฅผ ์ต์ ˆ ๋Œ€ํ‘œ๋กœ ๋‹จ์ •ํ•˜์ง€ ๋งˆ์„ธ์š”. ํ˜„์žฌ 0๊ฑด์ด๋ฏ€๋กœ ํ˜„ํ–‰ ํŒŒ๋ผ๋ฏธํ„ฐ ์œ ์ง€ ๋ฐ ์œ ๋‹ˆ๋ฒ„์Šค/๋ฐ์ดํ„ฐ ์ ๊ฒ€์ด ์šฐ์„ ์ž…๋‹ˆ๋‹ค. ์žฅ์„ธ ๋ณ€ํ™” ์‹œ ์†์ ˆ ์ž‘๋™ ์—ฌ๋ถ€๊ฐ€ ์Šน๋ฅ ๋ณด๋‹ค ์ค‘์š”ํ•จ์„ ๋ช…์‹ฌํ•˜์‹ญ์‹œ์˜ค. diff --git a/kis_trader/backtest/results/optuna_breakout_tpe_20260904_160123.briefing.md b/kis_trader/backtest/results/optuna_breakout_tpe_20260904_160123.briefing.md new file mode 100644 index 0000000..5507a7d --- /dev/null +++ b/kis_trader/backtest/results/optuna_breakout_tpe_20260904_160123.briefing.md @@ -0,0 +1,49 @@ +# Optuna ๋ธŒ๋ฆฌํ•‘ โ€” ๋ŒํŒŒ (tpe) +๊ธฐ๊ฐ„: 2026-08-31 ~ 2026-09-04 (๊ฑฐ๋ž˜์ผโ‰ˆ5์ผ) ยท trials 200/200 +ํƒ์ƒ‰ ๊ฒŒ์ดํŠธ: WRโ‰ฅ0% PFโ‰ฅ0 ยท min_tradesโ‰ฅ10 | ํ›„๋ณด ๊ฒŒ์ดํŠธ: WRโ‰ฅ40% PFโ‰ฅ1 ยท min_tradesโ‰ฅ10 +- min_trades=10: **ํ•ฉ๊ฒฉ ์ธ์ • ์ตœ์†Œ ๊ฑฐ๋ž˜ ๊ฑด์ˆ˜**(ํ‘œ๋ณธ ๋ถ€์กฑยท์šฐ์—ฐ ์Šน๋ฅ  ๋ฐฉ์ง€). ์ด๋ณด๋‹ค ์ ์€ ์กฐํ•ฉ์€ ํ•™์Šต/ํ›„๋ณด ์ง‘๊ณ„์—์„œ ์ œ์™ธ๋ฉ๋‹ˆ๋‹ค. +ํ•™์Šต์šฉ ํ†ต๊ณผ 0๊ฑด ยท ์‚ฌํ›„ํ•ฉ๊ฒฉ(results_gated) 0๊ฑด + +## ๊ณผ์ ํ•ฉยท์ ์šฉ ๊ฐ€๋Šฅ๋„ (ํœด๋ฆฌ์Šคํ‹ฑ) +- **๊ณผ์ ํ•ฉ ์œ„ํ—˜ 33.0%** ยท **์ ์šฉ ๊ฐ€๋Šฅ๋„ 67.0%** ยท ํŒ์ •: **์ƒ๋Œ€์ ์œผ๋กœ๋‚ฎ์Œ** โ€” ํœด๋ฆฌ์Šคํ‹ฑ์ƒ ์œ„ํ—˜ ์ƒ๋Œ€์  ๋‚ฎ์Œ โ€” ๊ทธ๋ž˜๋„ ๋‹ค์ผ ํ™•์ธ ๊ถŒ์žฅ + - ํ‘œ๋ณธ ์žฅ์ผ: +0.0p โ€” ๊ฑฐ๋ž˜์ผโ‰ˆ5์ผ โ€” ํ‘œ๋ณธ ์ผ์ˆ˜ ์ƒ๋Œ€์  ์–‘ํ˜ธ + - ๊ฑฐ๋ž˜ ํ‘œ๋ณธ: +25.0p โ€” ํ†ต๊ณผ ํ›„๋ณด ์—†์Œ โ€” ์ ์šฉ ๋ถˆ๊ฐ€ + - ์Šน๋ฅ ยทPF ์ด์ƒ์น˜: +0.0p โ€” ์ด์ƒ์น˜ ์—†์Œ + - ๊ฒŒ์ดํŠธ ์ปค๋ฒ„: +8.0p โ€” ํ•™์Šตยทgated ๋ชจ๋‘ ๋น„์–ด ์žˆ์Œ + - PnL ๊ณ ์›: +0.0p โ€” ๊ณ ์› ํŒ์ • ์Šคํ‚ต +- _์ฐธ๊ณ : ๊ณผ์ ํ•ฉ%๋Š” ๊ต์ฐจ๊ฒ€์ฆ ์ ์ˆ˜๊ฐ€ ์•„๋‹ˆ๋ผ ํ‘œ๋ณธยท์ด์ƒ์น˜ยท๊ณ ์› ํœด๋ฆฌ์Šคํ‹ฑ์ž…๋‹ˆ๋‹ค. ์ ์šฉ ๊ฐ€๋Šฅ๋„%=100โˆ’๊ณผ์ ํ•ฉ์œ„ํ—˜%. DB ์ ์šฉ ๋ฒ„ํŠผ ํ™œ์„ฑ ์กฐ๊ฑด(gated PnL>0)๊ณผ๋Š” ๋ณ„๊ฐœ์ž…๋‹ˆ๋‹ค._ + +## ์ตœ์ข… ์„ ํƒ ํ›„๋ณด (๊ทœ์น™ ยท DB ์ ์šฉ ์ „ ํ™•์ธ) +- ์•„๋ž˜๋Š” **์—ญํ• ์ด ๋‹ค๋ฅธ** 4์ข… ํ›„๋ณด์ž…๋‹ˆ๋‹ค. mode Top10 1์œ„ โ‰  ์ต์ ˆ ๋Œ€ํ‘œ ยท **DB 1์ˆœ์œ„๋Š” ์‚ฌํ›„ํ•ฉ๊ฒฉ(gated)** ์ž…๋‹ˆ๋‹ค. +- mode pool: `positive` ยท scoring: `band_proximity_p25_p75` + +### ํ›„๋ณด 4์ข… +- **โ‘  ์‚ฌํ›„ํ•ฉ๊ฒฉ 1์œ„ (apply: gated)**: ์—†์Œ +- **โ‘ก ์•ˆ์ • 1์œ„ (apply: stable)**: ์—†์Œ +- **โ‘ข mode_combo (apply: mode)**: ์—†์Œ (๋ฏธ์‚ฐ์ถœยท๊ตฌ JSON) +- **โ‘ฃ mode Top10 1์œ„ (apply: consensus ยท ๋ฐด๋“œ ์ „ํ˜• trial)**: ์—†์Œ +- mode Top10 meta: pool 0๊ฑด ยท ์ถ• 0๊ฐœ + +### ์ถ”์ฒœ (์ž๋™ ยท confirm ํ•„์ˆ˜) +1. **์‚ฌํ›„ํ•ฉ๊ฒฉ 0๊ฑด โ†’ DB ์ ์šฉ ๋น„๊ถŒ์žฅ.** ํ˜„ํ–‰ DB ์œ ์ง€ + ์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑยท๊ธฐ๊ฐ„ ์žฌ๊ฒ€์ฆ. +- โš  ์•ˆ์ • ๊ฒŒ์ดํŠธ 0๊ฑด โ†’ ์•ˆ์ • Top์€ **์ ์ˆ˜์ˆœ ํด๋ฐฑ** (์•ˆ์ • ๊ฒŒ์ดํŠธ 0๊ฑด โ†’ ํ•™์Šตํ’€ ์•ˆ์ •์ ์ˆ˜์ˆœ TopN (๋งˆ์ด๋„ˆ์Šค PnL ํฌํ•จ ยท ์ƒ๋Œ€๋น„๊ต)) + +## ์ด์ „ ์žฅ์—์„œ๋Š” +- ์‹ค๋งค ๋™๊ธฐ๊ฐ„ ์ฒญ์‚ฐ 30๊ฑด ยท ์Šน๋ฅ  27% ยท ํ•ฉ์‚ฐ PnL -82,108์› (๋ฐฑํ…Œ Optuna์™€ ์ˆซ์ž ๋‹ฌ๋ผ๋„ ์ •์ƒ โ€” ๊ณ ์ŠคํŠธยท์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑ ๊ฒฝ๋กœ ์ฐจ์ด). +- ์ด ๊ธฐ๊ฐ„ ๋ฐฑํ…Œ์—์„œ๋Š” **์œ ์˜๋ฏธํ•œ ํ†ต๊ณผ ์กฐํ•ฉ์ด ๊ฑฐ์˜ ์—†์—ˆ์Šต๋‹ˆ๋‹ค.** ์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑยท์†์ ˆยท์‹œ๊ฐ„์ฐฝ์„ ๋จผ์ € ์ ๊ฒ€ํ•˜์„ธ์š” (๋ŒํŒŒ 0๊ฑด์ด๋ฉด ํŠนํžˆ). + +## ์•ž์œผ๋กœ ์žฅ์—์„œ๋Š” +- **1~2์ผ Optuna best๋ฅผ ๋ฐ”๋กœ ์‹ค๋งค์— ๋„ฃ์ง€ ๋งˆ์„ธ์š”.** ๋‹ค์ผ(โ‰ฅ5๊ฑฐ๋ž˜์ผ) ์žฌ๊ฒ€์ฆยท์›น๋ฐฑํ…Œ 1ํšŒ ํ›„ ๊ฒ€ํ† . +- ์ ์šฉ ์‹œ์—๋Š” `results_gated` ํ›„๋ณด๋งŒ. ํƒ์ƒ‰์šฉ best(objective)์™€ ๋‹ค๋ฅผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. +- ์žฅ์ด ์ข์•„์ง€๊ฑฐ๋‚˜ ๋ณ€๋™์„ฑ์ด ์ปค์ง€๋ฉด: ์†์ ˆยทํŠธ๋ ˆ์ผยท์‹œ๊ฐ„์ฐฝ์ด ๋จผ์ € ๊นจ์ง‘๋‹ˆ๋‹ค. ์Šน๋ฅ  ์ž๋ž‘๋ณด๋‹ค **์†์ ˆ์ด ์‚ด์•„ ์žˆ๋Š”์ง€**๋ฅผ ๋ณด์„ธ์š”. +- ํ˜„์žฌ ์‚ฌํ›„ํ•ฉ๊ฒฉ 0๊ฑด โ†’ ํŒŒ๋ผ๋ฏธํ„ฐ ์œ ์ง€(ํ˜„ํ–‰ DB) + ์œ ๋‹ˆ๋ฒ„์Šค/๋ฐ์ดํ„ฐ ์ ๊ฒ€์ด ์šฐ์„ ์ž…๋‹ˆ๋‹ค. + +_์ƒ์„ฑ: 2026-09-04 16:01:23 (rule)_ + +## AI ์ฝ”๋ฉ˜ํŠธ (์ด์ „ ์žฅ / ์•ž์œผ๋กœ ์žฅ) [gemini] + +**ใ€Œ์ด์ „ ์žฅ์—์„œ๋Š”ใ€** +์งง์€ ๊ธฐ๊ฐ„(์•ฝ 5๊ฑฐ๋ž˜์ผ) ๋™์•ˆ ์‹ค๋งค๋Š” ์†์‹ค์„ ๊ธฐ๋กํ–ˆ์œผ๋ฉฐ, ๋ฐฑํ…Œ์ŠคํŠธ์—์„œ๋Š” `์ตœ์†Œ ๊ฑฐ๋ž˜ 10๊ฑด` ๊ธฐ์ค€์„ ๋งŒ์กฑํ•˜๋Š” `์œ ์˜๋ฏธํ•œ` ์กฐํ•ฉ์ด ์ „ํ˜€ ๋‚˜์˜ค์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. ๋ฐฑํ…Œ์ŠคํŠธ ๊ฒฐ๊ณผ์™€ ์‹ค์ œ ๋งค๋งค๋Š” ๊ณ ์ŠคํŠธํผ์ง€ ๋“ฑ ์—ฌ๋Ÿฌ ์š”์ธ์œผ๋กœ ์ˆซ์ž๊ฐ€ ๋‹ค๋ฅผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํŠนํžˆ `ํ•™์Šต/์‚ฌํ›„ํ•ฉ๊ฒฉ ํ†ต๊ณผ 0๊ฑด`์€ `๊ณผ์ ํ•ฉ ์œ„ํ—˜`๊ณผ `ํ‘œ๋ณธ ๋ถ€์กฑ`์„ ๊ฐ•ํ•˜๊ฒŒ ์‹œ์‚ฌํ•˜๋ฉฐ, ํ˜„ํ–‰ ์ „๋žต ์ ์šฉ์ด ๋งค์šฐ ์–ด๋ ต์Šต๋‹ˆ๋‹ค. + +**ใ€Œ์•ž์œผ๋กœ ์žฅ์—์„œ๋Š”ใ€** +์ด์ฒ˜๋Ÿผ `์‚ฌํ›„ํ•ฉ๊ฒฉ ํ›„๋ณด๊ฐ€ 0๊ฑด`์ผ ๋•Œ๋Š” `DB ์ ์šฉ์„ ๋น„๊ถŒ์žฅ`ํ•ฉ๋‹ˆ๋‹ค. ํ˜„์žฌ Optuna ๊ฒฐ๊ณผ๋Š” `์ ์šฉ ๋ถˆ๊ฐ€`๋กœ ํŒ๋‹จ๋˜๋ฏ€๋กœ, ํ˜„ํ–‰ DB๋ฅผ ์œ ์ง€ํ•˜๋ฉฐ ์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑ๋ฐ์ดํ„ฐยท์†์ ˆ ์กฐ๊ฑด ๋“ฑ์„ ์žฌ์ ๊ฒ€ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. `Mode Top10 1์œ„`๋ฅผ `์ต์ ˆ ๋Œ€ํ‘œ`๋กœ ๋‹จ์ •ํ•˜๊ธฐ ์–ด๋ ต๊ณ , `๊ฒฐ๊ณผ๋ฌผ์€ ์ถฉ๋ถ„ํ•œ ๋‹ค์ผ ๊ฒ€์ฆ(โ‰ฅ5๊ฑฐ๋ž˜์ผ) ํ›„, ์˜ค์ง ์‚ฌํ›„ํ•ฉ๊ฒฉ(gated) ํ›„๋ณด๋งŒ ์‹ค์ œ ๋งค๋งค ์ ์šฉ์„ ๊ณ ๋ ค`ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์–ด๋– ํ•œ ๊ฒฝ์šฐ์—๋„ `ํ™•์ • ์ˆ˜์ต์„ ์•ฝ์†`ํ•˜๊ฑฐ๋‚˜ `ํŠน์ • ์ข…๋ชฉ์„ ๋งค์ˆ˜ ์ถ”์ฒœ`ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. diff --git a/kis_trader/backtest/results/optuna_breakout_tpe_20260904_160917.briefing.md b/kis_trader/backtest/results/optuna_breakout_tpe_20260904_160917.briefing.md new file mode 100644 index 0000000..0ec5743 --- /dev/null +++ b/kis_trader/backtest/results/optuna_breakout_tpe_20260904_160917.briefing.md @@ -0,0 +1,51 @@ +# Optuna ๋ธŒ๋ฆฌํ•‘ โ€” ๋ŒํŒŒ (tpe) +๊ธฐ๊ฐ„: 2026-08-31 ~ 2026-09-04 (๊ฑฐ๋ž˜์ผโ‰ˆ5์ผ) ยท trials 200/200 +ํƒ์ƒ‰ ๊ฒŒ์ดํŠธ: WRโ‰ฅ0% PFโ‰ฅ0 ยท min_tradesโ‰ฅ10 | ํ›„๋ณด ๊ฒŒ์ดํŠธ: WRโ‰ฅ40% PFโ‰ฅ1 ยท min_tradesโ‰ฅ10 +- min_trades=10: **ํ•ฉ๊ฒฉ ์ธ์ • ์ตœ์†Œ ๊ฑฐ๋ž˜ ๊ฑด์ˆ˜**(ํ‘œ๋ณธ ๋ถ€์กฑยท์šฐ์—ฐ ์Šน๋ฅ  ๋ฐฉ์ง€). ์ด๋ณด๋‹ค ์ ์€ ์กฐํ•ฉ์€ ํ•™์Šต/ํ›„๋ณด ์ง‘๊ณ„์—์„œ ์ œ์™ธ๋ฉ๋‹ˆ๋‹ค. +ํ•™์Šต์šฉ ํ†ต๊ณผ 0๊ฑด ยท ์‚ฌํ›„ํ•ฉ๊ฒฉ(results_gated) 0๊ฑด + +## ๊ณผ์ ํ•ฉยท์ ์šฉ ๊ฐ€๋Šฅ๋„ (ํœด๋ฆฌ์Šคํ‹ฑ) +- **๊ณผ์ ํ•ฉ ์œ„ํ—˜ 33.0%** ยท **์ ์šฉ ๊ฐ€๋Šฅ๋„ 67.0%** ยท ํŒ์ •: **์ƒ๋Œ€์ ์œผ๋กœ๋‚ฎ์Œ** โ€” ํœด๋ฆฌ์Šคํ‹ฑ์ƒ ์œ„ํ—˜ ์ƒ๋Œ€์  ๋‚ฎ์Œ โ€” ๊ทธ๋ž˜๋„ ๋‹ค์ผ ํ™•์ธ ๊ถŒ์žฅ + - ํ‘œ๋ณธ ์žฅ์ผ: +0.0p โ€” ๊ฑฐ๋ž˜์ผโ‰ˆ5์ผ โ€” ํ‘œ๋ณธ ์ผ์ˆ˜ ์ƒ๋Œ€์  ์–‘ํ˜ธ + - ๊ฑฐ๋ž˜ ํ‘œ๋ณธ: +25.0p โ€” ํ†ต๊ณผ ํ›„๋ณด ์—†์Œ โ€” ์ ์šฉ ๋ถˆ๊ฐ€ + - ์Šน๋ฅ ยทPF ์ด์ƒ์น˜: +0.0p โ€” ์ด์ƒ์น˜ ์—†์Œ + - ๊ฒŒ์ดํŠธ ์ปค๋ฒ„: +8.0p โ€” ํ•™์Šตยทgated ๋ชจ๋‘ ๋น„์–ด ์žˆ์Œ + - PnL ๊ณ ์›: +0.0p โ€” ๊ณ ์› ํŒ์ • ์Šคํ‚ต +- _์ฐธ๊ณ : ๊ณผ์ ํ•ฉ%๋Š” ๊ต์ฐจ๊ฒ€์ฆ ์ ์ˆ˜๊ฐ€ ์•„๋‹ˆ๋ผ ํ‘œ๋ณธยท์ด์ƒ์น˜ยท๊ณ ์› ํœด๋ฆฌ์Šคํ‹ฑ์ž…๋‹ˆ๋‹ค. ์ ์šฉ ๊ฐ€๋Šฅ๋„%=100โˆ’๊ณผ์ ํ•ฉ์œ„ํ—˜%. DB ์ ์šฉ ๋ฒ„ํŠผ ํ™œ์„ฑ ์กฐ๊ฑด(gated PnL>0)๊ณผ๋Š” ๋ณ„๊ฐœ์ž…๋‹ˆ๋‹ค._ + +## ์ตœ์ข… ์„ ํƒ ํ›„๋ณด (๊ทœ์น™ ยท DB ์ ์šฉ ์ „ ํ™•์ธ) +- ์•„๋ž˜๋Š” **์—ญํ• ์ด ๋‹ค๋ฅธ** 4์ข… ํ›„๋ณด์ž…๋‹ˆ๋‹ค. mode Top10 1์œ„ โ‰  ์ต์ ˆ ๋Œ€ํ‘œ ยท **DB 1์ˆœ์œ„๋Š” ์‚ฌํ›„ํ•ฉ๊ฒฉ(gated)** ์ž…๋‹ˆ๋‹ค. +- mode pool: `positive` ยท scoring: `band_proximity_p25_p75` + +### ํ›„๋ณด 4์ข… +- **โ‘  ์‚ฌํ›„ํ•ฉ๊ฒฉ 1์œ„ (apply: gated)**: ์—†์Œ +- **โ‘ก ์•ˆ์ • 1์œ„ (apply: stable)**: ์—†์Œ +- **โ‘ข mode_combo (apply: mode)**: ์—†์Œ (๋ฏธ์‚ฐ์ถœยท๊ตฌ JSON) +- **โ‘ฃ mode Top10 1์œ„ (apply: consensus ยท ๋ฐด๋“œ ์ „ํ˜• trial)**: ์—†์Œ +- mode Top10 meta: pool 0๊ฑด ยท ์ถ• 0๊ฐœ + +### ์ถ”์ฒœ (์ž๋™ ยท confirm ํ•„์ˆ˜) +1. **์‚ฌํ›„ํ•ฉ๊ฒฉ 0๊ฑด โ†’ DB ์ ์šฉ ๋น„๊ถŒ์žฅ.** ํ˜„ํ–‰ DB ์œ ์ง€ + ์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑยท๊ธฐ๊ฐ„ ์žฌ๊ฒ€์ฆ. +- โš  ์•ˆ์ • ๊ฒŒ์ดํŠธ 0๊ฑด โ†’ ์•ˆ์ • Top์€ **์ ์ˆ˜์ˆœ ํด๋ฐฑ** (์•ˆ์ • ๊ฒŒ์ดํŠธ 0๊ฑด โ†’ ํ•™์Šตํ’€ ์•ˆ์ •์ ์ˆ˜์ˆœ TopN (๋งˆ์ด๋„ˆ์Šค PnL ํฌํ•จ ยท ์ƒ๋Œ€๋น„๊ต)) + +## ์ด์ „ ์žฅ์—์„œ๋Š” +- ์‹ค๋งค ๋™๊ธฐ๊ฐ„ ์ฒญ์‚ฐ 30๊ฑด ยท ์Šน๋ฅ  27% ยท ํ•ฉ์‚ฐ PnL -82,108์› (๋ฐฑํ…Œ Optuna์™€ ์ˆซ์ž ๋‹ฌ๋ผ๋„ ์ •์ƒ โ€” ๊ณ ์ŠคํŠธยท์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑ ๊ฒฝ๋กœ ์ฐจ์ด). +- ์ด ๊ธฐ๊ฐ„ ๋ฐฑํ…Œ์—์„œ๋Š” **์œ ์˜๋ฏธํ•œ ํ†ต๊ณผ ์กฐํ•ฉ์ด ๊ฑฐ์˜ ์—†์—ˆ์Šต๋‹ˆ๋‹ค.** ์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑยท์†์ ˆยท์‹œ๊ฐ„์ฐฝ์„ ๋จผ์ € ์ ๊ฒ€ํ•˜์„ธ์š” (๋ŒํŒŒ 0๊ฑด์ด๋ฉด ํŠนํžˆ). + +## ์•ž์œผ๋กœ ์žฅ์—์„œ๋Š” +- **1~2์ผ Optuna best๋ฅผ ๋ฐ”๋กœ ์‹ค๋งค์— ๋„ฃ์ง€ ๋งˆ์„ธ์š”.** ๋‹ค์ผ(โ‰ฅ5๊ฑฐ๋ž˜์ผ) ์žฌ๊ฒ€์ฆยท์›น๋ฐฑํ…Œ 1ํšŒ ํ›„ ๊ฒ€ํ† . +- ์ ์šฉ ์‹œ์—๋Š” `results_gated` ํ›„๋ณด๋งŒ. ํƒ์ƒ‰์šฉ best(objective)์™€ ๋‹ค๋ฅผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. +- ์žฅ์ด ์ข์•„์ง€๊ฑฐ๋‚˜ ๋ณ€๋™์„ฑ์ด ์ปค์ง€๋ฉด: ์†์ ˆยทํŠธ๋ ˆ์ผยท์‹œ๊ฐ„์ฐฝ์ด ๋จผ์ € ๊นจ์ง‘๋‹ˆ๋‹ค. ์Šน๋ฅ  ์ž๋ž‘๋ณด๋‹ค **์†์ ˆ์ด ์‚ด์•„ ์žˆ๋Š”์ง€**๋ฅผ ๋ณด์„ธ์š”. +- ํ˜„์žฌ ์‚ฌํ›„ํ•ฉ๊ฒฉ 0๊ฑด โ†’ ํŒŒ๋ผ๋ฏธํ„ฐ ์œ ์ง€(ํ˜„ํ–‰ DB) + ์œ ๋‹ˆ๋ฒ„์Šค/๋ฐ์ดํ„ฐ ์ ๊ฒ€์ด ์šฐ์„ ์ž…๋‹ˆ๋‹ค. + +_์ƒ์„ฑ: 2026-09-04 16:09:17 (rule)_ + +## AI ์ฝ”๋ฉ˜ํŠธ (์ด์ „ ์žฅ / ์•ž์œผ๋กœ ์žฅ) [gemini] + +## ์ด์ „ ์žฅ์—์„œ๋Š” + +์ง€๋‚œ 5๊ฑฐ๋ž˜์ผ๊ฐ„์˜ ์งง์€ ๊ธฐ๊ฐ„ ๋™์•ˆ ์ „๋žต ํƒ์ƒ‰์„ ์ง„ํ–‰ํ–ˆ์ง€๋งŒ, ์•„์‰ฝ๊ฒŒ๋„ ์ตœ์†Œ ๊ฑฐ๋ž˜ ๊ฑด์ˆ˜(10๊ฑด)๋ฅผ ์ถฉ์กฑํ•˜๋ฉฐ ์œ ์˜๋ฏธํ•œ ์„ฑ๊ณผ(์Šน๋ฅ  40%ยท์ˆ˜์ต PF 1)๋ฅผ ๋ณด์ธ **์ „๋žต ์กฐํ•ฉ์€ ๋‹จ ํ•˜๋‚˜๋„ ์ฐพ์ง€ ๋ชปํ–ˆ์Šต๋‹ˆ๋‹ค.** ์ด๋Š” ๋งค์šฐ **์งง์€ ๋ถ„์„ ๊ธฐ๊ฐ„์œผ๋กœ ์ธํ•œ ๊ทน์‹ฌํ•œ ํ‘œ๋ณธ ๋ถ€์กฑ**์œผ๋กœ, ์šฐ์—ฐํ•œ ์Šน๋ฅ ์ด ๊ฑธ๋Ÿฌ์ง€์ง€ ์•Š๋Š” ์œ„ํ—˜์„ ๋‚ดํฌํ•ฉ๋‹ˆ๋‹ค. ์‹ค๋งค๋งค์—์„œ๋Š” ์†์‹ค์ด ๋ฐœ์ƒํ–ˆ๋Š”๋ฐ, ๋ฐฑํ…Œ์ŠคํŠธ ๊ฒฐ๊ณผ๋งˆ์ € ์ „๋ฌดํ•˜๋‹ค๋Š” ์ ์€ **๋ฐฑํ…Œ์ŠคํŠธ์™€ ์‹ค์ œ ์‹œ์žฅ์˜ ๊ดด๋ฆฌ**๊ฐ€ ํฌ๋‹ค๋Š” ๊ฒฝ๊ณ  ์‹ ํ˜ธ๋กœ ๋ฐ›์•„๋“ค์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค. ํ˜„์žฌ๋กœ์„œ๋Š” **์ ์šฉํ•  ์ „๋žต์ด ์ „ํ˜€ ์—†์Šต๋‹ˆ๋‹ค.** + +## ์•ž์œผ๋กœ ์žฅ์—์„œ๋Š” + +ํ˜„์žฌ๋กœ์„œ๋Š” **DB์— ์ ์šฉํ•  ์ƒˆ๋กœ์šด ์ „๋žต์ด ์—†์Šต๋‹ˆ๋‹ค.** ๋”ฐ๋ผ์„œ ๊ธฐ์กด ์ „๋žต(ํ˜„ํ–‰ DB)์„ ์œ ์ง€ํ•˜๋ฉฐ, ์œ ๋‹ˆ๋ฒ„์Šค, ํ‹ฑ ๋ฐ์ดํ„ฐ, ์†์ ˆ๋งค ์„ค์ •, ๊ทธ๋ฆฌ๊ณ  ๋ถ„์„ ๊ธฐ๊ฐ„ ์ž์ฒด๋ฅผ **์ „๋ฉด์ ์œผ๋กœ ์žฌ๊ฒ€ํ† **ํ•˜๋Š” ๊ฒƒ์ด ์ตœ์šฐ์„ ์ž…๋‹ˆ๋‹ค. **๋‹จ 1~2์ผ ๋˜๋Š” 5๊ฑฐ๋ž˜์ผ ๊ฐ™์€ ์งง์€ ๊ธฐ๊ฐ„์˜ ๋ฐฑํ…Œ์ŠคํŠธ ๊ฒฐ๊ณผ๋ฅผ ๋งน์‹ ํ•˜๊ฑฐ๋‚˜ ๋ฐ”๋กœ ์‹ค๋งค๋งค์— ์ ์šฉํ•˜๋Š” ๊ฒƒ์€ ๊ณผ์ ํ•ฉ ๋ฐ ํ‘œ๋ณธ ๋ถ€์กฑ์˜ ์œ„ํ—˜์ด ๋งค์šฐ ํฌ๋ฏ€๋กœ ์ ˆ๋Œ€ ๊ธˆ์ง€**ํ•ฉ๋‹ˆ๋‹ค. **`mode Top10 1์œ„`๋Š” ๋‹จ์ˆœ ํ›„๋ณด ์ค‘ ํ•˜๋‚˜์ผ ๋ฟ ์ต์ ˆ ๋Œ€ํ‘œ๊ฐ€ ์•„๋‹ˆ๋ฉฐ, ์‚ฌํ›„ํ•ฉ๊ฒฉ(gated)๋œ ์ „๋žต๋งŒ์ด ์‹ ์ค‘ํ•œ ๊ฒ€ํ†  ๋Œ€์ƒ**์ž„์„ ๋‹ค์‹œ ํ•œ๋ฒˆ ๊ฐ•์กฐํ•ฉ๋‹ˆ๋‹ค. ์‹œ์žฅ ๋ณ€๋™์„ฑ์ด ์ปค์งˆ ๋•Œ๋Š” ์ˆ˜์ต๋ฅ ๋ณด๋‹ค **์†์ ˆ ๊ธฐ๋Šฅ์ด ์ œ๋Œ€๋กœ ์ž‘๋™ํ•˜๋Š”์ง€**๋ฅผ ์šฐ์„ ์ ์œผ๋กœ ํ™•์ธํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. diff --git a/kis_trader/backtest/results/optuna_breakout_tpe_20260904_161854.briefing.md b/kis_trader/backtest/results/optuna_breakout_tpe_20260904_161854.briefing.md new file mode 100644 index 0000000..fdbfff6 --- /dev/null +++ b/kis_trader/backtest/results/optuna_breakout_tpe_20260904_161854.briefing.md @@ -0,0 +1,49 @@ +# Optuna ๋ธŒ๋ฆฌํ•‘ โ€” ๋ŒํŒŒ (tpe) +๊ธฐ๊ฐ„: 2026-08-31 ~ 2026-09-04 (๊ฑฐ๋ž˜์ผโ‰ˆ5์ผ) ยท trials 200/200 +ํƒ์ƒ‰ ๊ฒŒ์ดํŠธ: WRโ‰ฅ0% PFโ‰ฅ0 ยท min_tradesโ‰ฅ10 | ํ›„๋ณด ๊ฒŒ์ดํŠธ: WRโ‰ฅ40% PFโ‰ฅ1 ยท min_tradesโ‰ฅ10 +- min_trades=10: **ํ•ฉ๊ฒฉ ์ธ์ • ์ตœ์†Œ ๊ฑฐ๋ž˜ ๊ฑด์ˆ˜**(ํ‘œ๋ณธ ๋ถ€์กฑยท์šฐ์—ฐ ์Šน๋ฅ  ๋ฐฉ์ง€). ์ด๋ณด๋‹ค ์ ์€ ์กฐํ•ฉ์€ ํ•™์Šต/ํ›„๋ณด ์ง‘๊ณ„์—์„œ ์ œ์™ธ๋ฉ๋‹ˆ๋‹ค. +ํ•™์Šต์šฉ ํ†ต๊ณผ 0๊ฑด ยท ์‚ฌํ›„ํ•ฉ๊ฒฉ(results_gated) 0๊ฑด + +## ๊ณผ์ ํ•ฉยท์ ์šฉ ๊ฐ€๋Šฅ๋„ (ํœด๋ฆฌ์Šคํ‹ฑ) +- **๊ณผ์ ํ•ฉ ์œ„ํ—˜ 33.0%** ยท **์ ์šฉ ๊ฐ€๋Šฅ๋„ 67.0%** ยท ํŒ์ •: **์ƒ๋Œ€์ ์œผ๋กœ๋‚ฎ์Œ** โ€” ํœด๋ฆฌ์Šคํ‹ฑ์ƒ ์œ„ํ—˜ ์ƒ๋Œ€์  ๋‚ฎ์Œ โ€” ๊ทธ๋ž˜๋„ ๋‹ค์ผ ํ™•์ธ ๊ถŒ์žฅ + - ํ‘œ๋ณธ ์žฅ์ผ: +0.0p โ€” ๊ฑฐ๋ž˜์ผโ‰ˆ5์ผ โ€” ํ‘œ๋ณธ ์ผ์ˆ˜ ์ƒ๋Œ€์  ์–‘ํ˜ธ + - ๊ฑฐ๋ž˜ ํ‘œ๋ณธ: +25.0p โ€” ํ†ต๊ณผ ํ›„๋ณด ์—†์Œ โ€” ์ ์šฉ ๋ถˆ๊ฐ€ + - ์Šน๋ฅ ยทPF ์ด์ƒ์น˜: +0.0p โ€” ์ด์ƒ์น˜ ์—†์Œ + - ๊ฒŒ์ดํŠธ ์ปค๋ฒ„: +8.0p โ€” ํ•™์Šตยทgated ๋ชจ๋‘ ๋น„์–ด ์žˆ์Œ + - PnL ๊ณ ์›: +0.0p โ€” ๊ณ ์› ํŒ์ • ์Šคํ‚ต +- _์ฐธ๊ณ : ๊ณผ์ ํ•ฉ%๋Š” ๊ต์ฐจ๊ฒ€์ฆ ์ ์ˆ˜๊ฐ€ ์•„๋‹ˆ๋ผ ํ‘œ๋ณธยท์ด์ƒ์น˜ยท๊ณ ์› ํœด๋ฆฌ์Šคํ‹ฑ์ž…๋‹ˆ๋‹ค. ์ ์šฉ ๊ฐ€๋Šฅ๋„%=100โˆ’๊ณผ์ ํ•ฉ์œ„ํ—˜%. DB ์ ์šฉ ๋ฒ„ํŠผ ํ™œ์„ฑ ์กฐ๊ฑด(gated PnL>0)๊ณผ๋Š” ๋ณ„๊ฐœ์ž…๋‹ˆ๋‹ค._ + +## ์ตœ์ข… ์„ ํƒ ํ›„๋ณด (๊ทœ์น™ ยท DB ์ ์šฉ ์ „ ํ™•์ธ) +- ์•„๋ž˜๋Š” **์—ญํ• ์ด ๋‹ค๋ฅธ** 4์ข… ํ›„๋ณด์ž…๋‹ˆ๋‹ค. mode Top10 1์œ„ โ‰  ์ต์ ˆ ๋Œ€ํ‘œ ยท **DB 1์ˆœ์œ„๋Š” ์‚ฌํ›„ํ•ฉ๊ฒฉ(gated)** ์ž…๋‹ˆ๋‹ค. +- mode pool: `positive` ยท scoring: `band_proximity_p25_p75` + +### ํ›„๋ณด 4์ข… +- **โ‘  ์‚ฌํ›„ํ•ฉ๊ฒฉ 1์œ„ (apply: gated)**: ์—†์Œ +- **โ‘ก ์•ˆ์ • 1์œ„ (apply: stable)**: ์—†์Œ +- **โ‘ข mode_combo (apply: mode)**: ์—†์Œ (๋ฏธ์‚ฐ์ถœยท๊ตฌ JSON) +- **โ‘ฃ mode Top10 1์œ„ (apply: consensus ยท ๋ฐด๋“œ ์ „ํ˜• trial)**: ์—†์Œ +- mode Top10 meta: pool 0๊ฑด ยท ์ถ• 0๊ฐœ + +### ์ถ”์ฒœ (์ž๋™ ยท confirm ํ•„์ˆ˜) +1. **์‚ฌํ›„ํ•ฉ๊ฒฉ 0๊ฑด โ†’ DB ์ ์šฉ ๋น„๊ถŒ์žฅ.** ํ˜„ํ–‰ DB ์œ ์ง€ + ์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑยท๊ธฐ๊ฐ„ ์žฌ๊ฒ€์ฆ. +- โš  ์•ˆ์ • ๊ฒŒ์ดํŠธ 0๊ฑด โ†’ ์•ˆ์ • Top์€ **์ ์ˆ˜์ˆœ ํด๋ฐฑ** (์•ˆ์ • ๊ฒŒ์ดํŠธ 0๊ฑด โ†’ ํ•™์Šตํ’€ ์•ˆ์ •์ ์ˆ˜์ˆœ TopN (๋งˆ์ด๋„ˆ์Šค PnL ํฌํ•จ ยท ์ƒ๋Œ€๋น„๊ต)) + +## ์ด์ „ ์žฅ์—์„œ๋Š” +- ์‹ค๋งค ๋™๊ธฐ๊ฐ„ ์ฒญ์‚ฐ 30๊ฑด ยท ์Šน๋ฅ  27% ยท ํ•ฉ์‚ฐ PnL -82,108์› (๋ฐฑํ…Œ Optuna์™€ ์ˆซ์ž ๋‹ฌ๋ผ๋„ ์ •์ƒ โ€” ๊ณ ์ŠคํŠธยท์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑ ๊ฒฝ๋กœ ์ฐจ์ด). +- ์ด ๊ธฐ๊ฐ„ ๋ฐฑํ…Œ์—์„œ๋Š” **์œ ์˜๋ฏธํ•œ ํ†ต๊ณผ ์กฐํ•ฉ์ด ๊ฑฐ์˜ ์—†์—ˆ์Šต๋‹ˆ๋‹ค.** ์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑยท์†์ ˆยท์‹œ๊ฐ„์ฐฝ์„ ๋จผ์ € ์ ๊ฒ€ํ•˜์„ธ์š” (๋ŒํŒŒ 0๊ฑด์ด๋ฉด ํŠนํžˆ). + +## ์•ž์œผ๋กœ ์žฅ์—์„œ๋Š” +- **1~2์ผ Optuna best๋ฅผ ๋ฐ”๋กœ ์‹ค๋งค์— ๋„ฃ์ง€ ๋งˆ์„ธ์š”.** ๋‹ค์ผ(โ‰ฅ5๊ฑฐ๋ž˜์ผ) ์žฌ๊ฒ€์ฆยท์›น๋ฐฑํ…Œ 1ํšŒ ํ›„ ๊ฒ€ํ† . +- ์ ์šฉ ์‹œ์—๋Š” `results_gated` ํ›„๋ณด๋งŒ. ํƒ์ƒ‰์šฉ best(objective)์™€ ๋‹ค๋ฅผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. +- ์žฅ์ด ์ข์•„์ง€๊ฑฐ๋‚˜ ๋ณ€๋™์„ฑ์ด ์ปค์ง€๋ฉด: ์†์ ˆยทํŠธ๋ ˆ์ผยท์‹œ๊ฐ„์ฐฝ์ด ๋จผ์ € ๊นจ์ง‘๋‹ˆ๋‹ค. ์Šน๋ฅ  ์ž๋ž‘๋ณด๋‹ค **์†์ ˆ์ด ์‚ด์•„ ์žˆ๋Š”์ง€**๋ฅผ ๋ณด์„ธ์š”. +- ํ˜„์žฌ ์‚ฌํ›„ํ•ฉ๊ฒฉ 0๊ฑด โ†’ ํŒŒ๋ผ๋ฏธํ„ฐ ์œ ์ง€(ํ˜„ํ–‰ DB) + ์œ ๋‹ˆ๋ฒ„์Šค/๋ฐ์ดํ„ฐ ์ ๊ฒ€์ด ์šฐ์„ ์ž…๋‹ˆ๋‹ค. + +_์ƒ์„ฑ: 2026-09-04 16:18:54 (rule)_ + +## AI ์ฝ”๋ฉ˜ํŠธ (์ด์ „ ์žฅ / ์•ž์œผ๋กœ ์žฅ) [gemini] + +## ์ด์ „ ์žฅ์—์„œ๋Š” +์ง€๋‚œ 5๊ฑฐ๋ž˜์ผ ๊ฐ„์˜ Optuna ๋ฐฑํ…Œ์ŠคํŠธ ๊ฒฐ๊ณผ, ์•„์‰ฝ๊ฒŒ๋„ ์ตœ์†Œ ๊ฑฐ๋ž˜ ๊ฑด์ˆ˜ ๋ฐ ์Šน๋ฅ ยท์†์ต๋น„ ๊ธฐ์ค€์„ ํ†ต๊ณผํ•œ ์œ ์˜๋ฏธํ•œ ์ „๋žต ์กฐํ•ฉ(์‚ฌํ›„ํ•ฉ๊ฒฉ 0๊ฑด)์€ ์ „ํ˜€ ๋ฐœ๊ฒฌ๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. ๋™ ๊ธฐ๊ฐ„ ์‹ค๋งค ์—ญ์‹œ ์ €์กฐํ–ˆ์Œ์„ ๊ณ ๋ คํ•  ๋•Œ, ์ด๋Š” **๋งค์šฐ ์งง์€ ๊ธฐ๊ฐ„(5์ผ)์œผ๋กœ ์ธํ•œ ๊ณผ์ ํ•ฉ ๋ฐ ํ‘œ๋ณธ ๋ถ€์กฑ ์œ„ํ—˜**์„ ๊ฐ•ํ•˜๊ฒŒ ๊ฒฝ๊ณ ํ•ฉ๋‹ˆ๋‹ค. ๋ฐฑํ…Œ์ŠคํŠธ ๊ฒฐ๊ณผ๋Š” **์‹ค์ œ ์‹œ์žฅ๊ณผ ํฐ ๊ดด๋ฆฌ**๋ฅผ ๋ณด์ผ ์ˆ˜ ์žˆ์œผ๋‹ˆ, ์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑยท์†์ ˆยท์‹œ๊ฐ„์ฐฝ์„ ํ•„ํžˆ ์žฌ์ ๊ฒ€ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. + +## ์•ž์œผ๋กœ ์žฅ์—์„œ๋Š” +์ด๋ฒˆ ๊ฒฐ๊ณผ๋กœ๋Š” DB ์ ์šฉ์„ ๋น„๊ถŒ์žฅํ•ฉ๋‹ˆ๋‹ค. **์‚ฌํ›„ํ•ฉ๊ฒฉ(gated)๋œ ์กฐํ•ฉ์ด 0๊ฑด**์ด๋ฏ€๋กœ, **์–ด๋–ค ํ›„๋ณด๋„ ์ต์ ˆ ๋Œ€ํ‘œ๋กœ ๋‹จ์ •ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.** ํŠนํžˆ mode Top10 1์œ„๋Š” ๋‹จ์ˆœ ์ ์ˆ˜์ˆœ ํ›„๋ณด์ผ ๋ฟ, ์‹ค๋งค ์ ์šฉ๊ณผ๋Š” ๊ฑฐ๋ฆฌ๊ฐ€ ๋ฉ€๊ณ  **๊ณผ์ ํ•ฉ ์œ„ํ—˜**์ด ํฝ๋‹ˆ๋‹ค. ํ–ฅํ›„ ์ตœ์†Œ 5๊ฑฐ๋ž˜์ผ ์ด์ƒ์˜ ๊ธฐ๊ฐ„์— ๊ฑธ์ณ ์žฌ๊ฒ€์ฆ ํ›„ `results_gated` ์กฐํ•ฉ๋งŒ์„ ์‹ ์ค‘ํžˆ ๊ฒ€ํ† ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ „๋žต์˜ **์†์ ˆ ๊ธฐ์ค€์ด ์œ ํšจํ•œ์ง€**๋ฅผ ์ตœ์šฐ์„ ์œผ๋กœ ์ ๊ฒ€ํ•˜๊ณ , ํ˜„ํ–‰ DB ์œ ์ง€์™€ ํ•จ๊ป˜ ์œ ๋‹ˆ๋ฒ„์Šค ๋ฐ ๋ฐ์ดํ„ฐ ์ ๊ฒ€์„ ์ง€์†ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. diff --git a/kis_trader/backtest/results/optuna_breakout_tpe_20260904_193931.briefing.md b/kis_trader/backtest/results/optuna_breakout_tpe_20260904_193931.briefing.md new file mode 100644 index 0000000..bd65c2a --- /dev/null +++ b/kis_trader/backtest/results/optuna_breakout_tpe_20260904_193931.briefing.md @@ -0,0 +1,49 @@ +# Optuna ๋ธŒ๋ฆฌํ•‘ โ€” ๋ŒํŒŒ (tpe) +๊ธฐ๊ฐ„: 2026-09-04 ~ 2026-09-04 (๊ฑฐ๋ž˜์ผโ‰ˆ1์ผ) ยท trials 200/200 +ํƒ์ƒ‰ ๊ฒŒ์ดํŠธ: WRโ‰ฅ0% PFโ‰ฅ0 ยท min_tradesโ‰ฅ2 | ํ›„๋ณด ๊ฒŒ์ดํŠธ: WRโ‰ฅ40% PFโ‰ฅ1 ยท min_tradesโ‰ฅ2 +- min_trades=2: **ํ•ฉ๊ฒฉ ์ธ์ • ์ตœ์†Œ ๊ฑฐ๋ž˜ ๊ฑด์ˆ˜**(ํ‘œ๋ณธ ๋ถ€์กฑยท์šฐ์—ฐ ์Šน๋ฅ  ๋ฐฉ์ง€). ์ด๋ณด๋‹ค ์ ์€ ์กฐํ•ฉ์€ ํ•™์Šต/ํ›„๋ณด ์ง‘๊ณ„์—์„œ ์ œ์™ธ๋ฉ๋‹ˆ๋‹ค. +ํ•™์Šต์šฉ ํ†ต๊ณผ 0๊ฑด ยท ์‚ฌํ›„ํ•ฉ๊ฒฉ(results_gated) 0๊ฑด + +## ๊ณผ์ ํ•ฉยท์ ์šฉ ๊ฐ€๋Šฅ๋„ (ํœด๋ฆฌ์Šคํ‹ฑ) +- **๊ณผ์ ํ•ฉ ์œ„ํ—˜ 73.0%** ยท **์ ์šฉ ๊ฐ€๋Šฅ๋„ 27.0%** ยท ํŒ์ •: **๋น„๊ถŒ์žฅ** โ€” ๊ณผ์ ํ•ฉยทํ‘œ๋ณธ๋ถ€์กฑ ์œ„ํ—˜ ๋†’์Œ โ€” ์‹ค๋งค DB ์ฆ‰์‹œ ์ ์šฉ ๋น„๊ถŒ์žฅ + - ํ‘œ๋ณธ ์žฅ์ผ: +40.0p โ€” ๊ฑฐ๋ž˜์ผโ‰ˆ1์ผ โ€” ๋‹จ์ผ ์žฅ ๊ณผ์ ํ•ฉ ์œ„ํ—˜ ์ตœ๋Œ€ + - ๊ฑฐ๋ž˜ ํ‘œ๋ณธ: +25.0p โ€” ํ†ต๊ณผ ํ›„๋ณด ์—†์Œ โ€” ์ ์šฉ ๋ถˆ๊ฐ€ + - ์Šน๋ฅ ยทPF ์ด์ƒ์น˜: +0.0p โ€” ์ด์ƒ์น˜ ์—†์Œ + - ๊ฒŒ์ดํŠธ ์ปค๋ฒ„: +8.0p โ€” ํ•™์Šตยทgated ๋ชจ๋‘ ๋น„์–ด ์žˆ์Œ + - PnL ๊ณ ์›: +0.0p โ€” ๊ณ ์› ํŒ์ • ์Šคํ‚ต +- _์ฐธ๊ณ : ๊ณผ์ ํ•ฉ%๋Š” ๊ต์ฐจ๊ฒ€์ฆ ์ ์ˆ˜๊ฐ€ ์•„๋‹ˆ๋ผ ํ‘œ๋ณธยท์ด์ƒ์น˜ยท๊ณ ์› ํœด๋ฆฌ์Šคํ‹ฑ์ž…๋‹ˆ๋‹ค. ์ ์šฉ ๊ฐ€๋Šฅ๋„%=100โˆ’๊ณผ์ ํ•ฉ์œ„ํ—˜%. DB ์ ์šฉ ๋ฒ„ํŠผ ํ™œ์„ฑ ์กฐ๊ฑด(gated PnL>0)๊ณผ๋Š” ๋ณ„๊ฐœ์ž…๋‹ˆ๋‹ค._ + +## ์ตœ์ข… ์„ ํƒ ํ›„๋ณด (๊ทœ์น™ ยท DB ์ ์šฉ ์ „ ํ™•์ธ) +- ์•„๋ž˜๋Š” **์—ญํ• ์ด ๋‹ค๋ฅธ** 4์ข… ํ›„๋ณด์ž…๋‹ˆ๋‹ค. mode Top10 1์œ„ โ‰  ์ต์ ˆ ๋Œ€ํ‘œ ยท **DB 1์ˆœ์œ„๋Š” ์‚ฌํ›„ํ•ฉ๊ฒฉ(gated)** ์ž…๋‹ˆ๋‹ค. +- mode pool: `positive` ยท scoring: `band_proximity_p25_p75` + +### ํ›„๋ณด 4์ข… +- **โ‘  ์‚ฌํ›„ํ•ฉ๊ฒฉ 1์œ„ (apply: gated)**: ์—†์Œ +- **โ‘ก ์•ˆ์ • 1์œ„ (apply: stable)**: ์—†์Œ +- **โ‘ข mode_combo (apply: mode)**: ์—†์Œ (๋ฏธ์‚ฐ์ถœยท๊ตฌ JSON) +- **โ‘ฃ mode Top10 1์œ„ (apply: consensus ยท ๋ฐด๋“œ ์ „ํ˜• trial)**: ์—†์Œ +- mode Top10 meta: pool 0๊ฑด ยท ์ถ• 0๊ฐœ + +### ์ถ”์ฒœ (์ž๋™ ยท confirm ํ•„์ˆ˜) +1. **์‚ฌํ›„ํ•ฉ๊ฒฉ 0๊ฑด โ†’ DB ์ ์šฉ ๋น„๊ถŒ์žฅ.** ํ˜„ํ–‰ DB ์œ ์ง€ + ์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑยท๊ธฐ๊ฐ„ ์žฌ๊ฒ€์ฆ. +- โš  ์•ˆ์ • ๊ฒŒ์ดํŠธ 0๊ฑด โ†’ ์•ˆ์ • Top์€ **์ ์ˆ˜์ˆœ ํด๋ฐฑ** (์•ˆ์ • ๊ฒŒ์ดํŠธ 0๊ฑด โ†’ ํ•™์Šตํ’€ ์•ˆ์ •์ ์ˆ˜์ˆœ TopN (๋งˆ์ด๋„ˆ์Šค PnL ํฌํ•จ ยท ์ƒ๋Œ€๋น„๊ต)) + +## ์ด์ „ ์žฅ์—์„œ๋Š” +- ์‹ค๋งค ๋™๊ธฐ๊ฐ„ ์ฒญ์‚ฐ 13๊ฑด ยท ์Šน๋ฅ  31% ยท ํ•ฉ์‚ฐ PnL -34,618์› (๋ฐฑํ…Œ Optuna์™€ ์ˆซ์ž ๋‹ฌ๋ผ๋„ ์ •์ƒ โ€” ๊ณ ์ŠคํŠธยท์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑ ๊ฒฝ๋กœ ์ฐจ์ด). +- ์ด ๊ธฐ๊ฐ„ ๋ฐฑํ…Œ์—์„œ๋Š” **์œ ์˜๋ฏธํ•œ ํ†ต๊ณผ ์กฐํ•ฉ์ด ๊ฑฐ์˜ ์—†์—ˆ์Šต๋‹ˆ๋‹ค.** ์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑยท์†์ ˆยท์‹œ๊ฐ„์ฐฝ์„ ๋จผ์ € ์ ๊ฒ€ํ•˜์„ธ์š” (๋ŒํŒŒ 0๊ฑด์ด๋ฉด ํŠนํžˆ). + +## ์•ž์œผ๋กœ ์žฅ์—์„œ๋Š” +- **1~2์ผ Optuna best๋ฅผ ๋ฐ”๋กœ ์‹ค๋งค์— ๋„ฃ์ง€ ๋งˆ์„ธ์š”.** ๋‹ค์ผ(โ‰ฅ5๊ฑฐ๋ž˜์ผ) ์žฌ๊ฒ€์ฆยท์›น๋ฐฑํ…Œ 1ํšŒ ํ›„ ๊ฒ€ํ† . +- ์ ์šฉ ์‹œ์—๋Š” `results_gated` ํ›„๋ณด๋งŒ. ํƒ์ƒ‰์šฉ best(objective)์™€ ๋‹ค๋ฅผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. +- ์žฅ์ด ์ข์•„์ง€๊ฑฐ๋‚˜ ๋ณ€๋™์„ฑ์ด ์ปค์ง€๋ฉด: ์†์ ˆยทํŠธ๋ ˆ์ผยท์‹œ๊ฐ„์ฐฝ์ด ๋จผ์ € ๊นจ์ง‘๋‹ˆ๋‹ค. ์Šน๋ฅ  ์ž๋ž‘๋ณด๋‹ค **์†์ ˆ์ด ์‚ด์•„ ์žˆ๋Š”์ง€**๋ฅผ ๋ณด์„ธ์š”. +- ํ˜„์žฌ ์‚ฌํ›„ํ•ฉ๊ฒฉ 0๊ฑด โ†’ ํŒŒ๋ผ๋ฏธํ„ฐ ์œ ์ง€(ํ˜„ํ–‰ DB) + ์œ ๋‹ˆ๋ฒ„์Šค/๋ฐ์ดํ„ฐ ์ ๊ฒ€์ด ์šฐ์„ ์ž…๋‹ˆ๋‹ค. + +_์ƒ์„ฑ: 2026-09-04 19:39:31 (rule)_ + +## AI ์ฝ”๋ฉ˜ํŠธ (์ด์ „ ์žฅ / ์•ž์œผ๋กœ ์žฅ) [gemini] + +**์ด์ „ ์žฅ์—์„œ๋Š”** +๋‹จ ํ•˜๋ฃจ(2026-09-04) ๋ฐฑํ…Œ์ŠคํŠธ๋กœ ๊ณผ์ ํ•ฉ ์œ„ํ—˜ 73%, ํ‘œ๋ณธ ๋ถ€์กฑ์ด ์‹ฌ๊ฐํ–ˆ์Šต๋‹ˆ๋‹ค. ์œ ํšจํ•œ ํ•™์Šต/์‚ฌํ›„ํ•ฉ๊ฒฉ ์ „๋žต์ด ์ „๋ฌดํ•˜์—ฌ ์‹ค๋งค ์ ์šฉ์€ ๋น„๊ถŒ์žฅ๋ฉ๋‹ˆ๋‹ค. ์‹ค๋งค๋Š” 31% ์Šน๋ฅ , -3.4๋งŒ์› ์†์‹ค์„ ๊ธฐ๋ก, ๋ฐฑํ…Œ์ŠคํŠธ์™€์˜ ๊ดด๋ฆฌ(๊ณ ์ŠคํŠธ ์Šฌ๋ฆฌํ”ผ์ง€ ๋“ฑ)๋ฅผ ์žฌํ™•์ธํ–ˆ์Šต๋‹ˆ๋‹ค. ์œ ๋‹ˆ๋ฒ„์Šค/ํ‹ฑ/๊ธฐ๊ฐ„ ์žฌ์ ๊ฒ€์ด ์‹œ๊ธ‰ํ•ฉ๋‹ˆ๋‹ค. + +**์•ž์œผ๋กœ ์žฅ์—์„œ๋Š”** +1~2์ผ Optuna ๊ฒฐ๊ณผ๋Š” ๊ณผ์ ํ•ฉ ์œ„ํ—˜์ด ๋†’์•„ ์‹ค๋งค์— ๋ฐ”๋กœ ๋„ฃ์ง€ ๋งˆ์‹ญ์‹œ์˜ค. ์ตœ์†Œ 5๊ฑฐ๋ž˜์ผ ์ด์ƒ ์žฌ๊ฒ€์ฆ์ด ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค. `mode Top10 1์œ„`๋Š” ์ต์ ˆ ๋Œ€ํ‘œ๊ฐ€ ์•„๋‹ˆ๋ฉฐ, `์‚ฌํ›„ํ•ฉ๊ฒฉ(gated)` ์ „๋žต์ด 0๊ฑด์ด๋ฏ€๋กœ ํ˜„ํ–‰ DB ์œ ์ง€ ๋ฐ ์œ ๋‹ˆ๋ฒ„์Šค/๋ฐ์ดํ„ฐ ์ ๊ฒ€์ด ์šฐ์„ ์ž…๋‹ˆ๋‹ค. ํ™•์ • ์ˆ˜์ต ์•ฝ์†์€ ๋ถˆ๊ฐ€ํ•˜๋ฉฐ, ์†์ ˆ ์ค€์ˆ˜ ์—ฌ๋ถ€๋ฅผ ํ•ญ์ƒ ์ ๊ฒ€ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. diff --git a/kis_trader/backtest/results/optuna_breakout_tpe_20260904_194124.briefing.md b/kis_trader/backtest/results/optuna_breakout_tpe_20260904_194124.briefing.md new file mode 100644 index 0000000..72f7820 --- /dev/null +++ b/kis_trader/backtest/results/optuna_breakout_tpe_20260904_194124.briefing.md @@ -0,0 +1,51 @@ +# Optuna ๋ธŒ๋ฆฌํ•‘ โ€” ๋ŒํŒŒ (tpe) +๊ธฐ๊ฐ„: 2026-09-04 ~ 2026-09-04 (๊ฑฐ๋ž˜์ผโ‰ˆ1์ผ) ยท trials 200/200 +ํƒ์ƒ‰ ๊ฒŒ์ดํŠธ: WRโ‰ฅ0% PFโ‰ฅ0 ยท min_tradesโ‰ฅ2 | ํ›„๋ณด ๊ฒŒ์ดํŠธ: WRโ‰ฅ40% PFโ‰ฅ1 ยท min_tradesโ‰ฅ2 +- min_trades=2: **ํ•ฉ๊ฒฉ ์ธ์ • ์ตœ์†Œ ๊ฑฐ๋ž˜ ๊ฑด์ˆ˜**(ํ‘œ๋ณธ ๋ถ€์กฑยท์šฐ์—ฐ ์Šน๋ฅ  ๋ฐฉ์ง€). ์ด๋ณด๋‹ค ์ ์€ ์กฐํ•ฉ์€ ํ•™์Šต/ํ›„๋ณด ์ง‘๊ณ„์—์„œ ์ œ์™ธ๋ฉ๋‹ˆ๋‹ค. +ํ•™์Šต์šฉ ํ†ต๊ณผ 0๊ฑด ยท ์‚ฌํ›„ํ•ฉ๊ฒฉ(results_gated) 0๊ฑด + +## ๊ณผ์ ํ•ฉยท์ ์šฉ ๊ฐ€๋Šฅ๋„ (ํœด๋ฆฌ์Šคํ‹ฑ) +- **๊ณผ์ ํ•ฉ ์œ„ํ—˜ 73.0%** ยท **์ ์šฉ ๊ฐ€๋Šฅ๋„ 27.0%** ยท ํŒ์ •: **๋น„๊ถŒ์žฅ** โ€” ๊ณผ์ ํ•ฉยทํ‘œ๋ณธ๋ถ€์กฑ ์œ„ํ—˜ ๋†’์Œ โ€” ์‹ค๋งค DB ์ฆ‰์‹œ ์ ์šฉ ๋น„๊ถŒ์žฅ + - ํ‘œ๋ณธ ์žฅ์ผ: +40.0p โ€” ๊ฑฐ๋ž˜์ผโ‰ˆ1์ผ โ€” ๋‹จ์ผ ์žฅ ๊ณผ์ ํ•ฉ ์œ„ํ—˜ ์ตœ๋Œ€ + - ๊ฑฐ๋ž˜ ํ‘œ๋ณธ: +25.0p โ€” ํ†ต๊ณผ ํ›„๋ณด ์—†์Œ โ€” ์ ์šฉ ๋ถˆ๊ฐ€ + - ์Šน๋ฅ ยทPF ์ด์ƒ์น˜: +0.0p โ€” ์ด์ƒ์น˜ ์—†์Œ + - ๊ฒŒ์ดํŠธ ์ปค๋ฒ„: +8.0p โ€” ํ•™์Šตยทgated ๋ชจ๋‘ ๋น„์–ด ์žˆ์Œ + - PnL ๊ณ ์›: +0.0p โ€” ๊ณ ์› ํŒ์ • ์Šคํ‚ต +- _์ฐธ๊ณ : ๊ณผ์ ํ•ฉ%๋Š” ๊ต์ฐจ๊ฒ€์ฆ ์ ์ˆ˜๊ฐ€ ์•„๋‹ˆ๋ผ ํ‘œ๋ณธยท์ด์ƒ์น˜ยท๊ณ ์› ํœด๋ฆฌ์Šคํ‹ฑ์ž…๋‹ˆ๋‹ค. ์ ์šฉ ๊ฐ€๋Šฅ๋„%=100โˆ’๊ณผ์ ํ•ฉ์œ„ํ—˜%. DB ์ ์šฉ ๋ฒ„ํŠผ ํ™œ์„ฑ ์กฐ๊ฑด(gated PnL>0)๊ณผ๋Š” ๋ณ„๊ฐœ์ž…๋‹ˆ๋‹ค._ + +## ์ตœ์ข… ์„ ํƒ ํ›„๋ณด (๊ทœ์น™ ยท DB ์ ์šฉ ์ „ ํ™•์ธ) +- ์•„๋ž˜๋Š” **์—ญํ• ์ด ๋‹ค๋ฅธ** 4์ข… ํ›„๋ณด์ž…๋‹ˆ๋‹ค. mode Top10 1์œ„ โ‰  ์ต์ ˆ ๋Œ€ํ‘œ ยท **DB 1์ˆœ์œ„๋Š” ์‚ฌํ›„ํ•ฉ๊ฒฉ(gated)** ์ž…๋‹ˆ๋‹ค. +- mode pool: `positive` ยท scoring: `band_proximity_p25_p75` + +### ํ›„๋ณด 4์ข… +- **โ‘  ์‚ฌํ›„ํ•ฉ๊ฒฉ 1์œ„ (apply: gated)**: ์—†์Œ +- **โ‘ก ์•ˆ์ • 1์œ„ (apply: stable)**: ์—†์Œ +- **โ‘ข mode_combo (apply: mode)**: ์—†์Œ (๋ฏธ์‚ฐ์ถœยท๊ตฌ JSON) +- **โ‘ฃ mode Top10 1์œ„ (apply: consensus ยท ๋ฐด๋“œ ์ „ํ˜• trial)**: ์—†์Œ +- mode Top10 meta: pool 0๊ฑด ยท ์ถ• 0๊ฐœ + +### ์ถ”์ฒœ (์ž๋™ ยท confirm ํ•„์ˆ˜) +1. **์‚ฌํ›„ํ•ฉ๊ฒฉ 0๊ฑด โ†’ DB ์ ์šฉ ๋น„๊ถŒ์žฅ.** ํ˜„ํ–‰ DB ์œ ์ง€ + ์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑยท๊ธฐ๊ฐ„ ์žฌ๊ฒ€์ฆ. +- โš  ์•ˆ์ • ๊ฒŒ์ดํŠธ 0๊ฑด โ†’ ์•ˆ์ • Top์€ **์ ์ˆ˜์ˆœ ํด๋ฐฑ** (์•ˆ์ • ๊ฒŒ์ดํŠธ 0๊ฑด โ†’ ํ•™์Šตํ’€ ์•ˆ์ •์ ์ˆ˜์ˆœ TopN (๋งˆ์ด๋„ˆ์Šค PnL ํฌํ•จ ยท ์ƒ๋Œ€๋น„๊ต)) + +## ์ด์ „ ์žฅ์—์„œ๋Š” +- ์‹ค๋งค ๋™๊ธฐ๊ฐ„ ์ฒญ์‚ฐ 13๊ฑด ยท ์Šน๋ฅ  31% ยท ํ•ฉ์‚ฐ PnL -34,618์› (๋ฐฑํ…Œ Optuna์™€ ์ˆซ์ž ๋‹ฌ๋ผ๋„ ์ •์ƒ โ€” ๊ณ ์ŠคํŠธยท์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑ ๊ฒฝ๋กœ ์ฐจ์ด). +- ์ด ๊ธฐ๊ฐ„ ๋ฐฑํ…Œ์—์„œ๋Š” **์œ ์˜๋ฏธํ•œ ํ†ต๊ณผ ์กฐํ•ฉ์ด ๊ฑฐ์˜ ์—†์—ˆ์Šต๋‹ˆ๋‹ค.** ์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑยท์†์ ˆยท์‹œ๊ฐ„์ฐฝ์„ ๋จผ์ € ์ ๊ฒ€ํ•˜์„ธ์š” (๋ŒํŒŒ 0๊ฑด์ด๋ฉด ํŠนํžˆ). + +## ์•ž์œผ๋กœ ์žฅ์—์„œ๋Š” +- **1~2์ผ Optuna best๋ฅผ ๋ฐ”๋กœ ์‹ค๋งค์— ๋„ฃ์ง€ ๋งˆ์„ธ์š”.** ๋‹ค์ผ(โ‰ฅ5๊ฑฐ๋ž˜์ผ) ์žฌ๊ฒ€์ฆยท์›น๋ฐฑํ…Œ 1ํšŒ ํ›„ ๊ฒ€ํ† . +- ์ ์šฉ ์‹œ์—๋Š” `results_gated` ํ›„๋ณด๋งŒ. ํƒ์ƒ‰์šฉ best(objective)์™€ ๋‹ค๋ฅผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. +- ์žฅ์ด ์ข์•„์ง€๊ฑฐ๋‚˜ ๋ณ€๋™์„ฑ์ด ์ปค์ง€๋ฉด: ์†์ ˆยทํŠธ๋ ˆ์ผยท์‹œ๊ฐ„์ฐฝ์ด ๋จผ์ € ๊นจ์ง‘๋‹ˆ๋‹ค. ์Šน๋ฅ  ์ž๋ž‘๋ณด๋‹ค **์†์ ˆ์ด ์‚ด์•„ ์žˆ๋Š”์ง€**๋ฅผ ๋ณด์„ธ์š”. +- ํ˜„์žฌ ์‚ฌํ›„ํ•ฉ๊ฒฉ 0๊ฑด โ†’ ํŒŒ๋ผ๋ฏธํ„ฐ ์œ ์ง€(ํ˜„ํ–‰ DB) + ์œ ๋‹ˆ๋ฒ„์Šค/๋ฐ์ดํ„ฐ ์ ๊ฒ€์ด ์šฐ์„ ์ž…๋‹ˆ๋‹ค. + +_์ƒ์„ฑ: 2026-09-04 19:41:24 (rule)_ + +## AI ์ฝ”๋ฉ˜ํŠธ (์ด์ „ ์žฅ / ์•ž์œผ๋กœ ์žฅ) [gemini] + +## ์ด์ „ ์žฅ์—์„œ๋Š” + +์ง€๋‚œ ์žฅ์—์„œ๋Š” ๋‹จ 1์ผ์˜ ๋ฐฑํ…Œ์ŠคํŠธ ๊ฒฐ๊ณผ, **์‚ฌํ›„ ํ•ฉ๊ฒฉ๋œ ์กฐํ•ฉ์ด ์ „ํ˜€ ์—†์—ˆ์Šต๋‹ˆ๋‹ค.** ์ด๋Š” **๊ณผ์ ํ•ฉ ์œ„ํ—˜ 73%**์™€ **ํ‘œ๋ณธ ๋ถ€์กฑ**์œผ๋กœ ์ธํ•œ ๊ฒƒ์œผ๋กœ, ์‹ค์ œ ์‹œ์žฅ์—์„œ ์œ ํšจํ•œ ์ „๋žต์„ ์ฐพ๊ธฐ ๋งค์šฐ ์–ด๋ ค์› ์Œ์„ ์‹œ์‚ฌํ•ฉ๋‹ˆ๋‹ค. ์‹ค๋งค ๋™๊ธฐ๊ฐ„ ์ฒญ์‚ฐ ๋ฐ์ดํ„ฐ(-34,618์›)์™€ ๋ฐฑํ…Œ์ŠคํŠธ ์ˆ˜์น˜๋Š” ๊ณ ์ŠคํŠธํผ์ง€ ๋“ฑ ๋‹ค์–‘ํ•œ ๊ดด๋ฆฌ๊ฐ€ ์žˆ์œผ๋‹ˆ ์ง์ ‘ ๋น„๊ต๋Š” ์ฃผ์˜ํ•˜์„ธ์š”. + +## ์•ž์œผ๋กœ ์žฅ์—์„œ๋Š” + +์ด ๋‹จ๊ธฐ ๋ฐฑํ…Œ์ŠคํŠธ ๊ฒฐ๊ณผ๋Š” **์‹ค๋งค ์ ์šฉ์— ๋ถ€์ ํ•ฉ**ํ•ฉ๋‹ˆ๋‹ค. ๋‹จ 1์ผ ๋ฐ์ดํ„ฐ๋Š” **๊ณผ์ ํ•ฉ** ๋ฐ **ํ‘œ๋ณธ ๋ถ€์กฑ** ์œ„ํ—˜์ด ๋งค์šฐ ๋†’์•„, ๋ฐฑํ…Œ์ŠคํŠธ ์Šน๋ฅ ์ด ์‹ค์ œ ์ˆ˜์ต์œผ๋กœ ์ด์–ด์งˆ ๊ฐ€๋Šฅ์„ฑ์ด ๊ทนํžˆ ๋‚ฎ์Šต๋‹ˆ๋‹ค. ๋ฐ˜๋“œ์‹œ ๋‹ค์ˆ˜ ๊ฑฐ๋ž˜์ผ์˜ ์›น๋ฐฑํ…Œ์ŠคํŠธ๋ฅผ ํ†ตํ•ด ์ „๋žต์˜ ์•ˆ์ •์„ฑ์„ ์žฌ๊ฒ€์ฆํ•˜๊ณ , **์‚ฌํ›„ํ•ฉ๊ฒฉ(gated)**๋œ ํ›„๋ณด๋งŒ ์‹ ์ค‘ํžˆ ๊ณ ๋ คํ•˜์‹ญ์‹œ์˜ค. **mode Top10 1์œ„**๊ฐ€ ์•„๋‹Œ **์‚ฌํ›„ํ•ฉ๊ฒฉ DB 1์ˆœ์œ„**๋งŒ์ด ์‹ค๋งค ์ ์šฉ ํ›„๋ณด์ž…๋‹ˆ๋‹ค. ํŠน์ • ์ข…๋ชฉ ๋งค์ˆ˜ ์ถ”์ฒœ์ด๋‚˜ ํ™•์ • ์ˆ˜์ต ์•ฝ์†์€ ๋ถˆ๊ฐ€ํ•ฉ๋‹ˆ๋‹ค. diff --git a/kis_trader/backtest/results/optuna_breakout_tpe_20260904_195419.briefing.md b/kis_trader/backtest/results/optuna_breakout_tpe_20260904_195419.briefing.md new file mode 100644 index 0000000..a16b1cd --- /dev/null +++ b/kis_trader/backtest/results/optuna_breakout_tpe_20260904_195419.briefing.md @@ -0,0 +1,49 @@ +# Optuna ๋ธŒ๋ฆฌํ•‘ โ€” ๋ŒํŒŒ (tpe) +๊ธฐ๊ฐ„: 2026-09-04 ~ 2026-09-04 (๊ฑฐ๋ž˜์ผโ‰ˆ1์ผ) ยท trials 200/200 +ํƒ์ƒ‰ ๊ฒŒ์ดํŠธ: WRโ‰ฅ0% PFโ‰ฅ0 ยท min_tradesโ‰ฅ2 | ํ›„๋ณด ๊ฒŒ์ดํŠธ: WRโ‰ฅ40% PFโ‰ฅ1 ยท min_tradesโ‰ฅ2 +- min_trades=2: **ํ•ฉ๊ฒฉ ์ธ์ • ์ตœ์†Œ ๊ฑฐ๋ž˜ ๊ฑด์ˆ˜**(ํ‘œ๋ณธ ๋ถ€์กฑยท์šฐ์—ฐ ์Šน๋ฅ  ๋ฐฉ์ง€). ์ด๋ณด๋‹ค ์ ์€ ์กฐํ•ฉ์€ ํ•™์Šต/ํ›„๋ณด ์ง‘๊ณ„์—์„œ ์ œ์™ธ๋ฉ๋‹ˆ๋‹ค. +ํ•™์Šต์šฉ ํ†ต๊ณผ 0๊ฑด ยท ์‚ฌํ›„ํ•ฉ๊ฒฉ(results_gated) 0๊ฑด + +## ๊ณผ์ ํ•ฉยท์ ์šฉ ๊ฐ€๋Šฅ๋„ (ํœด๋ฆฌ์Šคํ‹ฑ) +- **๊ณผ์ ํ•ฉ ์œ„ํ—˜ 73.0%** ยท **์ ์šฉ ๊ฐ€๋Šฅ๋„ 27.0%** ยท ํŒ์ •: **๋น„๊ถŒ์žฅ** โ€” ๊ณผ์ ํ•ฉยทํ‘œ๋ณธ๋ถ€์กฑ ์œ„ํ—˜ ๋†’์Œ โ€” ์‹ค๋งค DB ์ฆ‰์‹œ ์ ์šฉ ๋น„๊ถŒ์žฅ + - ํ‘œ๋ณธ ์žฅ์ผ: +40.0p โ€” ๊ฑฐ๋ž˜์ผโ‰ˆ1์ผ โ€” ๋‹จ์ผ ์žฅ ๊ณผ์ ํ•ฉ ์œ„ํ—˜ ์ตœ๋Œ€ + - ๊ฑฐ๋ž˜ ํ‘œ๋ณธ: +25.0p โ€” ํ†ต๊ณผ ํ›„๋ณด ์—†์Œ โ€” ์ ์šฉ ๋ถˆ๊ฐ€ + - ์Šน๋ฅ ยทPF ์ด์ƒ์น˜: +0.0p โ€” ์ด์ƒ์น˜ ์—†์Œ + - ๊ฒŒ์ดํŠธ ์ปค๋ฒ„: +8.0p โ€” ํ•™์Šตยทgated ๋ชจ๋‘ ๋น„์–ด ์žˆ์Œ + - PnL ๊ณ ์›: +0.0p โ€” ๊ณ ์› ํŒ์ • ์Šคํ‚ต +- _์ฐธ๊ณ : ๊ณผ์ ํ•ฉ%๋Š” ๊ต์ฐจ๊ฒ€์ฆ ์ ์ˆ˜๊ฐ€ ์•„๋‹ˆ๋ผ ํ‘œ๋ณธยท์ด์ƒ์น˜ยท๊ณ ์› ํœด๋ฆฌ์Šคํ‹ฑ์ž…๋‹ˆ๋‹ค. ์ ์šฉ ๊ฐ€๋Šฅ๋„%=100โˆ’๊ณผ์ ํ•ฉ์œ„ํ—˜%. DB ์ ์šฉ ๋ฒ„ํŠผ ํ™œ์„ฑ ์กฐ๊ฑด(gated PnL>0)๊ณผ๋Š” ๋ณ„๊ฐœ์ž…๋‹ˆ๋‹ค._ + +## ์ตœ์ข… ์„ ํƒ ํ›„๋ณด (๊ทœ์น™ ยท DB ์ ์šฉ ์ „ ํ™•์ธ) +- ์•„๋ž˜๋Š” **์—ญํ• ์ด ๋‹ค๋ฅธ** 4์ข… ํ›„๋ณด์ž…๋‹ˆ๋‹ค. mode Top10 1์œ„ โ‰  ์ต์ ˆ ๋Œ€ํ‘œ ยท **DB 1์ˆœ์œ„๋Š” ์‚ฌํ›„ํ•ฉ๊ฒฉ(gated)** ์ž…๋‹ˆ๋‹ค. +- mode pool: `positive` ยท scoring: `band_proximity_p25_p75` + +### ํ›„๋ณด 4์ข… +- **โ‘  ์‚ฌํ›„ํ•ฉ๊ฒฉ 1์œ„ (apply: gated)**: ์—†์Œ +- **โ‘ก ์•ˆ์ • 1์œ„ (apply: stable)**: ์—†์Œ +- **โ‘ข mode_combo (apply: mode)**: ์—†์Œ (๋ฏธ์‚ฐ์ถœยท๊ตฌ JSON) +- **โ‘ฃ mode Top10 1์œ„ (apply: consensus ยท ๋ฐด๋“œ ์ „ํ˜• trial)**: ์—†์Œ +- mode Top10 meta: pool 0๊ฑด ยท ์ถ• 0๊ฐœ + +### ์ถ”์ฒœ (์ž๋™ ยท confirm ํ•„์ˆ˜) +1. **์‚ฌํ›„ํ•ฉ๊ฒฉ 0๊ฑด โ†’ DB ์ ์šฉ ๋น„๊ถŒ์žฅ.** ํ˜„ํ–‰ DB ์œ ์ง€ + ์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑยท๊ธฐ๊ฐ„ ์žฌ๊ฒ€์ฆ. +- โš  ์•ˆ์ • ๊ฒŒ์ดํŠธ 0๊ฑด โ†’ ์•ˆ์ • Top์€ **์ ์ˆ˜์ˆœ ํด๋ฐฑ** (์•ˆ์ • ๊ฒŒ์ดํŠธ 0๊ฑด โ†’ ํ•™์Šตํ’€ ์•ˆ์ •์ ์ˆ˜์ˆœ TopN (๋งˆ์ด๋„ˆ์Šค PnL ํฌํ•จ ยท ์ƒ๋Œ€๋น„๊ต)) + +## ์ด์ „ ์žฅ์—์„œ๋Š” +- ์‹ค๋งค ๋™๊ธฐ๊ฐ„ ์ฒญ์‚ฐ 13๊ฑด ยท ์Šน๋ฅ  31% ยท ํ•ฉ์‚ฐ PnL -34,618์› (๋ฐฑํ…Œ Optuna์™€ ์ˆซ์ž ๋‹ฌ๋ผ๋„ ์ •์ƒ โ€” ๊ณ ์ŠคํŠธยท์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑ ๊ฒฝ๋กœ ์ฐจ์ด). +- ์ด ๊ธฐ๊ฐ„ ๋ฐฑํ…Œ์—์„œ๋Š” **์œ ์˜๋ฏธํ•œ ํ†ต๊ณผ ์กฐํ•ฉ์ด ๊ฑฐ์˜ ์—†์—ˆ์Šต๋‹ˆ๋‹ค.** ์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑยท์†์ ˆยท์‹œ๊ฐ„์ฐฝ์„ ๋จผ์ € ์ ๊ฒ€ํ•˜์„ธ์š” (๋ŒํŒŒ 0๊ฑด์ด๋ฉด ํŠนํžˆ). + +## ์•ž์œผ๋กœ ์žฅ์—์„œ๋Š” +- **1~2์ผ Optuna best๋ฅผ ๋ฐ”๋กœ ์‹ค๋งค์— ๋„ฃ์ง€ ๋งˆ์„ธ์š”.** ๋‹ค์ผ(โ‰ฅ5๊ฑฐ๋ž˜์ผ) ์žฌ๊ฒ€์ฆยท์›น๋ฐฑํ…Œ 1ํšŒ ํ›„ ๊ฒ€ํ† . +- ์ ์šฉ ์‹œ์—๋Š” `results_gated` ํ›„๋ณด๋งŒ. ํƒ์ƒ‰์šฉ best(objective)์™€ ๋‹ค๋ฅผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. +- ์žฅ์ด ์ข์•„์ง€๊ฑฐ๋‚˜ ๋ณ€๋™์„ฑ์ด ์ปค์ง€๋ฉด: ์†์ ˆยทํŠธ๋ ˆ์ผยท์‹œ๊ฐ„์ฐฝ์ด ๋จผ์ € ๊นจ์ง‘๋‹ˆ๋‹ค. ์Šน๋ฅ  ์ž๋ž‘๋ณด๋‹ค **์†์ ˆ์ด ์‚ด์•„ ์žˆ๋Š”์ง€**๋ฅผ ๋ณด์„ธ์š”. +- ํ˜„์žฌ ์‚ฌํ›„ํ•ฉ๊ฒฉ 0๊ฑด โ†’ ํŒŒ๋ผ๋ฏธํ„ฐ ์œ ์ง€(ํ˜„ํ–‰ DB) + ์œ ๋‹ˆ๋ฒ„์Šค/๋ฐ์ดํ„ฐ ์ ๊ฒ€์ด ์šฐ์„ ์ž…๋‹ˆ๋‹ค. + +_์ƒ์„ฑ: 2026-09-04 19:54:19 (rule)_ + +## AI ์ฝ”๋ฉ˜ํŠธ (์ด์ „ ์žฅ / ์•ž์œผ๋กœ ์žฅ) [gemini] + +## ์ด์ „ ์žฅ์—์„œ๋Š” +์ด์ „ ์˜ตํŠœ๋‚˜ ํƒ์ƒ‰์€ ๋‹จ ํ•˜๋ฃจ(2026-09-04) ๋ฐ์ดํ„ฐ๋กœ **๊ณผ์ ํ•ฉ ์œ„ํ—˜ 73%**์— ๋‹ฌํ–ˆ์Šต๋‹ˆ๋‹ค. ๋ฐฑํ…Œ์ŠคํŠธ ํ†ต๊ณผ ์กฐํ•ฉ์ด ์ „๋ฌดํ•˜์—ฌ **ํ‘œ๋ณธ ๋ถ€์กฑ**์ด ์‹ฌ๊ฐํ•˜๊ณ , ์‹ค์ œ ํŠธ๋ ˆ์ด๋”ฉ๋„ ์†์‹ค์ด์—ˆ์Šต๋‹ˆ๋‹ค. ์‹ค๋งค์™€ ๋ฐฑํ…Œ ๊ฐ„ **๊ดด๋ฆฌ(๊ณ ์ŠคํŠธํผ์ง€)**๋„ ๋ถ„๋ช…ํžˆ ๊ฒฝ๊ณ ํ•ฉ๋‹ˆ๋‹ค. + +## ์•ž์œผ๋กœ ์žฅ์—์„œ๋Š” +๋‹จ๊ธฐ ๋ฐฑํ…Œ์ŠคํŠธ ๊ฒฐ๊ณผ๋Š” **๊ณผ์ ํ•ฉ ๋ฐ ํ‘œ๋ณธ ๋ถ€์กฑ** ์œ„ํ—˜์ด ์ปค ์‹ค๋งค ์ ์šฉ ์‹œ **๋ฐฑํ…Œ์™€ ๋‹ค๋ฅธ ๊ดด๋ฆฌ**๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. `mode Top10 1์œ„`๋ฅผ ์ต์ ˆ ๋Œ€ํ‘œ๋กœ ๋ณด์ง€ ๋งˆ์‹œ๊ณ , `์‚ฌํ›„ํ•ฉ๊ฒฉ(gated)` ํ›„๋ณด๋งŒ ์‹ ์ค‘ํžˆ ๊ฒ€ํ† ํ•˜์„ธ์š”. ํ˜„์žฌ๋Š” ํ˜„ํ–‰ DB ์œ ์ง€ ๋ฐ ์œ ๋‹ˆ๋ฒ„์Šค/๋ฐ์ดํ„ฐ ๊ฒ€์ฆ์ด ์šฐ์„ ์ž…๋‹ˆ๋‹ค. diff --git a/kis_trader/backtest/results/optuna_breakout_tpe_20260904_195612.briefing.md b/kis_trader/backtest/results/optuna_breakout_tpe_20260904_195612.briefing.md new file mode 100644 index 0000000..0cfb61d --- /dev/null +++ b/kis_trader/backtest/results/optuna_breakout_tpe_20260904_195612.briefing.md @@ -0,0 +1,49 @@ +# Optuna ๋ธŒ๋ฆฌํ•‘ โ€” ๋ŒํŒŒ (tpe) +๊ธฐ๊ฐ„: 2026-09-04 ~ 2026-09-04 (๊ฑฐ๋ž˜์ผโ‰ˆ1์ผ) ยท trials 200/200 +ํƒ์ƒ‰ ๊ฒŒ์ดํŠธ: WRโ‰ฅ0% PFโ‰ฅ0 ยท min_tradesโ‰ฅ2 | ํ›„๋ณด ๊ฒŒ์ดํŠธ: WRโ‰ฅ40% PFโ‰ฅ1 ยท min_tradesโ‰ฅ2 +- min_trades=2: **ํ•ฉ๊ฒฉ ์ธ์ • ์ตœ์†Œ ๊ฑฐ๋ž˜ ๊ฑด์ˆ˜**(ํ‘œ๋ณธ ๋ถ€์กฑยท์šฐ์—ฐ ์Šน๋ฅ  ๋ฐฉ์ง€). ์ด๋ณด๋‹ค ์ ์€ ์กฐํ•ฉ์€ ํ•™์Šต/ํ›„๋ณด ์ง‘๊ณ„์—์„œ ์ œ์™ธ๋ฉ๋‹ˆ๋‹ค. +ํ•™์Šต์šฉ ํ†ต๊ณผ 0๊ฑด ยท ์‚ฌํ›„ํ•ฉ๊ฒฉ(results_gated) 0๊ฑด + +## ๊ณผ์ ํ•ฉยท์ ์šฉ ๊ฐ€๋Šฅ๋„ (ํœด๋ฆฌ์Šคํ‹ฑ) +- **๊ณผ์ ํ•ฉ ์œ„ํ—˜ 73.0%** ยท **์ ์šฉ ๊ฐ€๋Šฅ๋„ 27.0%** ยท ํŒ์ •: **๋น„๊ถŒ์žฅ** โ€” ๊ณผ์ ํ•ฉยทํ‘œ๋ณธ๋ถ€์กฑ ์œ„ํ—˜ ๋†’์Œ โ€” ์‹ค๋งค DB ์ฆ‰์‹œ ์ ์šฉ ๋น„๊ถŒ์žฅ + - ํ‘œ๋ณธ ์žฅ์ผ: +40.0p โ€” ๊ฑฐ๋ž˜์ผโ‰ˆ1์ผ โ€” ๋‹จ์ผ ์žฅ ๊ณผ์ ํ•ฉ ์œ„ํ—˜ ์ตœ๋Œ€ + - ๊ฑฐ๋ž˜ ํ‘œ๋ณธ: +25.0p โ€” ํ†ต๊ณผ ํ›„๋ณด ์—†์Œ โ€” ์ ์šฉ ๋ถˆ๊ฐ€ + - ์Šน๋ฅ ยทPF ์ด์ƒ์น˜: +0.0p โ€” ์ด์ƒ์น˜ ์—†์Œ + - ๊ฒŒ์ดํŠธ ์ปค๋ฒ„: +8.0p โ€” ํ•™์Šตยทgated ๋ชจ๋‘ ๋น„์–ด ์žˆ์Œ + - PnL ๊ณ ์›: +0.0p โ€” ๊ณ ์› ํŒ์ • ์Šคํ‚ต +- _์ฐธ๊ณ : ๊ณผ์ ํ•ฉ%๋Š” ๊ต์ฐจ๊ฒ€์ฆ ์ ์ˆ˜๊ฐ€ ์•„๋‹ˆ๋ผ ํ‘œ๋ณธยท์ด์ƒ์น˜ยท๊ณ ์› ํœด๋ฆฌ์Šคํ‹ฑ์ž…๋‹ˆ๋‹ค. ์ ์šฉ ๊ฐ€๋Šฅ๋„%=100โˆ’๊ณผ์ ํ•ฉ์œ„ํ—˜%. DB ์ ์šฉ ๋ฒ„ํŠผ ํ™œ์„ฑ ์กฐ๊ฑด(gated PnL>0)๊ณผ๋Š” ๋ณ„๊ฐœ์ž…๋‹ˆ๋‹ค._ + +## ์ตœ์ข… ์„ ํƒ ํ›„๋ณด (๊ทœ์น™ ยท DB ์ ์šฉ ์ „ ํ™•์ธ) +- ์•„๋ž˜๋Š” **์—ญํ• ์ด ๋‹ค๋ฅธ** 4์ข… ํ›„๋ณด์ž…๋‹ˆ๋‹ค. mode Top10 1์œ„ โ‰  ์ต์ ˆ ๋Œ€ํ‘œ ยท **DB 1์ˆœ์œ„๋Š” ์‚ฌํ›„ํ•ฉ๊ฒฉ(gated)** ์ž…๋‹ˆ๋‹ค. +- mode pool: `positive` ยท scoring: `band_proximity_p25_p75` + +### ํ›„๋ณด 4์ข… +- **โ‘  ์‚ฌํ›„ํ•ฉ๊ฒฉ 1์œ„ (apply: gated)**: ์—†์Œ +- **โ‘ก ์•ˆ์ • 1์œ„ (apply: stable)**: ์—†์Œ +- **โ‘ข mode_combo (apply: mode)**: ์—†์Œ (๋ฏธ์‚ฐ์ถœยท๊ตฌ JSON) +- **โ‘ฃ mode Top10 1์œ„ (apply: consensus ยท ๋ฐด๋“œ ์ „ํ˜• trial)**: ์—†์Œ +- mode Top10 meta: pool 0๊ฑด ยท ์ถ• 0๊ฐœ + +### ์ถ”์ฒœ (์ž๋™ ยท confirm ํ•„์ˆ˜) +1. **์‚ฌํ›„ํ•ฉ๊ฒฉ 0๊ฑด โ†’ DB ์ ์šฉ ๋น„๊ถŒ์žฅ.** ํ˜„ํ–‰ DB ์œ ์ง€ + ์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑยท๊ธฐ๊ฐ„ ์žฌ๊ฒ€์ฆ. +- โš  ์•ˆ์ • ๊ฒŒ์ดํŠธ 0๊ฑด โ†’ ์•ˆ์ • Top์€ **์ ์ˆ˜์ˆœ ํด๋ฐฑ** (์•ˆ์ • ๊ฒŒ์ดํŠธ 0๊ฑด โ†’ ํ•™์Šตํ’€ ์•ˆ์ •์ ์ˆ˜์ˆœ TopN (๋งˆ์ด๋„ˆ์Šค PnL ํฌํ•จ ยท ์ƒ๋Œ€๋น„๊ต)) + +## ์ด์ „ ์žฅ์—์„œ๋Š” +- ์‹ค๋งค ๋™๊ธฐ๊ฐ„ ์ฒญ์‚ฐ 13๊ฑด ยท ์Šน๋ฅ  31% ยท ํ•ฉ์‚ฐ PnL -34,618์› (๋ฐฑํ…Œ Optuna์™€ ์ˆซ์ž ๋‹ฌ๋ผ๋„ ์ •์ƒ โ€” ๊ณ ์ŠคํŠธยท์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑ ๊ฒฝ๋กœ ์ฐจ์ด). +- ์ด ๊ธฐ๊ฐ„ ๋ฐฑํ…Œ์—์„œ๋Š” **์œ ์˜๋ฏธํ•œ ํ†ต๊ณผ ์กฐํ•ฉ์ด ๊ฑฐ์˜ ์—†์—ˆ์Šต๋‹ˆ๋‹ค.** ์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑยท์†์ ˆยท์‹œ๊ฐ„์ฐฝ์„ ๋จผ์ € ์ ๊ฒ€ํ•˜์„ธ์š” (๋ŒํŒŒ 0๊ฑด์ด๋ฉด ํŠนํžˆ). + +## ์•ž์œผ๋กœ ์žฅ์—์„œ๋Š” +- **1~2์ผ Optuna best๋ฅผ ๋ฐ”๋กœ ์‹ค๋งค์— ๋„ฃ์ง€ ๋งˆ์„ธ์š”.** ๋‹ค์ผ(โ‰ฅ5๊ฑฐ๋ž˜์ผ) ์žฌ๊ฒ€์ฆยท์›น๋ฐฑํ…Œ 1ํšŒ ํ›„ ๊ฒ€ํ† . +- ์ ์šฉ ์‹œ์—๋Š” `results_gated` ํ›„๋ณด๋งŒ. ํƒ์ƒ‰์šฉ best(objective)์™€ ๋‹ค๋ฅผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. +- ์žฅ์ด ์ข์•„์ง€๊ฑฐ๋‚˜ ๋ณ€๋™์„ฑ์ด ์ปค์ง€๋ฉด: ์†์ ˆยทํŠธ๋ ˆ์ผยท์‹œ๊ฐ„์ฐฝ์ด ๋จผ์ € ๊นจ์ง‘๋‹ˆ๋‹ค. ์Šน๋ฅ  ์ž๋ž‘๋ณด๋‹ค **์†์ ˆ์ด ์‚ด์•„ ์žˆ๋Š”์ง€**๋ฅผ ๋ณด์„ธ์š”. +- ํ˜„์žฌ ์‚ฌํ›„ํ•ฉ๊ฒฉ 0๊ฑด โ†’ ํŒŒ๋ผ๋ฏธํ„ฐ ์œ ์ง€(ํ˜„ํ–‰ DB) + ์œ ๋‹ˆ๋ฒ„์Šค/๋ฐ์ดํ„ฐ ์ ๊ฒ€์ด ์šฐ์„ ์ž…๋‹ˆ๋‹ค. + +_์ƒ์„ฑ: 2026-09-04 19:56:12 (rule)_ + +## AI ์ฝ”๋ฉ˜ํŠธ (์ด์ „ ์žฅ / ์•ž์œผ๋กœ ์žฅ) [gemini] + +**์ด์ „ ์žฅ์—์„œ๋Š”** +๋‹จ ํ•˜๋ฃจ ๋ฐฑํ…Œ์ŠคํŠธ ๊ฒฐ๊ณผ๋Š” ๊ณผ์ ํ•ฉ ์œ„ํ—˜ 73% ๋ฐ ํ‘œ๋ณธ ๋ถ€์กฑ์œผ๋กœ ์œ ์˜๋ฏธํ•œ ์ „๋žต์ด ์ „๋ฌดํ•ฉ๋‹ˆ๋‹ค. ์‹ค๋งค ์†์‹ค๊ณผ ๋ฐฑํ…Œ์ŠคํŠธ ๊ฐ„์˜ ๊ดด๋ฆฌ๋„ ํฌ๋ฏ€๋กœ, ํ˜„์žฌ DB ์ ์šฉ์€ ๋น„๊ถŒ์žฅ๋ฉ๋‹ˆ๋‹ค. ์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑ ๋“ฑ ๊ธฐ๋ณธ ์„ค์ •์„ ์žฌ์ ๊ฒ€ํ•ด์ฃผ์„ธ์š”. + +**์•ž์œผ๋กœ ์žฅ์—์„œ๋Š”** +์‚ฌํ›„ํ•ฉ๊ฒฉ(gated) ํ›„๋ณด๊ฐ€ 0๊ฑด์ด๋ฏ€๋กœ Optuna ๊ฒฐ๊ณผ๋ฅผ ์‹ค๋งค์— ์ฆ‰์‹œ ์ ์šฉํ•ด์„  ์•ˆ ๋ฉ๋‹ˆ๋‹ค. `mode Top10 1์œ„`๋Š” ์ต์ ˆ ๋Œ€ํ‘œ๊ฐ€ ์•„๋‹ˆ๋ฉฐ, DB 1์ˆœ์œ„๋Š” ์‚ฌํ›„ํ•ฉ๊ฒฉ(gated) ํ›„๋ณด๋ฟ์ž…๋‹ˆ๋‹ค. ๊ณผ์ ํ•ฉยทํ‘œ๋ณธ๋ถ€์กฑยท์‹ค๋งคโ†”๋ฐฑํ…Œ ๊ดด๋ฆฌ ์œ„ํ—˜์ด ๋งค์šฐ ๋†’์œผ๋‹ˆ, ์ตœ์†Œ 5๊ฑฐ๋ž˜์ผ ์ด์ƒ ์žฌ๊ฒ€์ฆ ํ›„ ์‹ ์ค‘ํžˆ ๊ฒ€ํ† ํ•˜์„ธ์š”. ํ™•์ • ์ˆ˜์ต ์•ฝ์†์ด๋‚˜ ํŠน์ • ์ข…๋ชฉ ์ถ”์ฒœ์€ ๋ถˆ๊ฐ€ํ•ฉ๋‹ˆ๋‹ค. diff --git a/kis_trader/backtest/results/optuna_breakout_tpe_20260904_201345.briefing.md b/kis_trader/backtest/results/optuna_breakout_tpe_20260904_201345.briefing.md new file mode 100644 index 0000000..e8f20ff --- /dev/null +++ b/kis_trader/backtest/results/optuna_breakout_tpe_20260904_201345.briefing.md @@ -0,0 +1,49 @@ +# Optuna ๋ธŒ๋ฆฌํ•‘ โ€” ๋ŒํŒŒ (tpe) +๊ธฐ๊ฐ„: 2026-09-04 ~ 2026-09-04 (๊ฑฐ๋ž˜์ผโ‰ˆ1์ผ) ยท trials 200/200 +ํƒ์ƒ‰ ๊ฒŒ์ดํŠธ: WRโ‰ฅ0% PFโ‰ฅ0 ยท min_tradesโ‰ฅ2 | ํ›„๋ณด ๊ฒŒ์ดํŠธ: WRโ‰ฅ40% PFโ‰ฅ1 ยท min_tradesโ‰ฅ2 +- min_trades=2: **ํ•ฉ๊ฒฉ ์ธ์ • ์ตœ์†Œ ๊ฑฐ๋ž˜ ๊ฑด์ˆ˜**(ํ‘œ๋ณธ ๋ถ€์กฑยท์šฐ์—ฐ ์Šน๋ฅ  ๋ฐฉ์ง€). ์ด๋ณด๋‹ค ์ ์€ ์กฐํ•ฉ์€ ํ•™์Šต/ํ›„๋ณด ์ง‘๊ณ„์—์„œ ์ œ์™ธ๋ฉ๋‹ˆ๋‹ค. +ํ•™์Šต์šฉ ํ†ต๊ณผ 0๊ฑด ยท ์‚ฌํ›„ํ•ฉ๊ฒฉ(results_gated) 0๊ฑด + +## ๊ณผ์ ํ•ฉยท์ ์šฉ ๊ฐ€๋Šฅ๋„ (ํœด๋ฆฌ์Šคํ‹ฑ) +- **๊ณผ์ ํ•ฉ ์œ„ํ—˜ 73.0%** ยท **์ ์šฉ ๊ฐ€๋Šฅ๋„ 27.0%** ยท ํŒ์ •: **๋น„๊ถŒ์žฅ** โ€” ๊ณผ์ ํ•ฉยทํ‘œ๋ณธ๋ถ€์กฑ ์œ„ํ—˜ ๋†’์Œ โ€” ์‹ค๋งค DB ์ฆ‰์‹œ ์ ์šฉ ๋น„๊ถŒ์žฅ + - ํ‘œ๋ณธ ์žฅ์ผ: +40.0p โ€” ๊ฑฐ๋ž˜์ผโ‰ˆ1์ผ โ€” ๋‹จ์ผ ์žฅ ๊ณผ์ ํ•ฉ ์œ„ํ—˜ ์ตœ๋Œ€ + - ๊ฑฐ๋ž˜ ํ‘œ๋ณธ: +25.0p โ€” ํ†ต๊ณผ ํ›„๋ณด ์—†์Œ โ€” ์ ์šฉ ๋ถˆ๊ฐ€ + - ์Šน๋ฅ ยทPF ์ด์ƒ์น˜: +0.0p โ€” ์ด์ƒ์น˜ ์—†์Œ + - ๊ฒŒ์ดํŠธ ์ปค๋ฒ„: +8.0p โ€” ํ•™์Šตยทgated ๋ชจ๋‘ ๋น„์–ด ์žˆ์Œ + - PnL ๊ณ ์›: +0.0p โ€” ๊ณ ์› ํŒ์ • ์Šคํ‚ต +- _์ฐธ๊ณ : ๊ณผ์ ํ•ฉ%๋Š” ๊ต์ฐจ๊ฒ€์ฆ ์ ์ˆ˜๊ฐ€ ์•„๋‹ˆ๋ผ ํ‘œ๋ณธยท์ด์ƒ์น˜ยท๊ณ ์› ํœด๋ฆฌ์Šคํ‹ฑ์ž…๋‹ˆ๋‹ค. ์ ์šฉ ๊ฐ€๋Šฅ๋„%=100โˆ’๊ณผ์ ํ•ฉ์œ„ํ—˜%. DB ์ ์šฉ ๋ฒ„ํŠผ ํ™œ์„ฑ ์กฐ๊ฑด(gated PnL>0)๊ณผ๋Š” ๋ณ„๊ฐœ์ž…๋‹ˆ๋‹ค._ + +## ์ตœ์ข… ์„ ํƒ ํ›„๋ณด (๊ทœ์น™ ยท DB ์ ์šฉ ์ „ ํ™•์ธ) +- ์•„๋ž˜๋Š” **์—ญํ• ์ด ๋‹ค๋ฅธ** 4์ข… ํ›„๋ณด์ž…๋‹ˆ๋‹ค. mode Top10 1์œ„ โ‰  ์ต์ ˆ ๋Œ€ํ‘œ ยท **DB 1์ˆœ์œ„๋Š” ์‚ฌํ›„ํ•ฉ๊ฒฉ(gated)** ์ž…๋‹ˆ๋‹ค. +- mode pool: `positive` ยท scoring: `band_proximity_p25_p75` + +### ํ›„๋ณด 4์ข… +- **โ‘  ์‚ฌํ›„ํ•ฉ๊ฒฉ 1์œ„ (apply: gated)**: ์—†์Œ +- **โ‘ก ์•ˆ์ • 1์œ„ (apply: stable)**: ์—†์Œ +- **โ‘ข mode_combo (apply: mode)**: ์—†์Œ (๋ฏธ์‚ฐ์ถœยท๊ตฌ JSON) +- **โ‘ฃ mode Top10 1์œ„ (apply: consensus ยท ๋ฐด๋“œ ์ „ํ˜• trial)**: ์—†์Œ +- mode Top10 meta: pool 0๊ฑด ยท ์ถ• 0๊ฐœ + +### ์ถ”์ฒœ (์ž๋™ ยท confirm ํ•„์ˆ˜) +1. **์‚ฌํ›„ํ•ฉ๊ฒฉ 0๊ฑด โ†’ DB ์ ์šฉ ๋น„๊ถŒ์žฅ.** ํ˜„ํ–‰ DB ์œ ์ง€ + ์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑยท๊ธฐ๊ฐ„ ์žฌ๊ฒ€์ฆ. +- โš  ์•ˆ์ • ๊ฒŒ์ดํŠธ 0๊ฑด โ†’ ์•ˆ์ • Top์€ **์ ์ˆ˜์ˆœ ํด๋ฐฑ** (์•ˆ์ • ๊ฒŒ์ดํŠธ 0๊ฑด โ†’ ํ•™์Šตํ’€ ์•ˆ์ •์ ์ˆ˜์ˆœ TopN (๋งˆ์ด๋„ˆ์Šค PnL ํฌํ•จ ยท ์ƒ๋Œ€๋น„๊ต)) + +## ์ด์ „ ์žฅ์—์„œ๋Š” +- ์‹ค๋งค ๋™๊ธฐ๊ฐ„ ์ฒญ์‚ฐ 13๊ฑด ยท ์Šน๋ฅ  31% ยท ํ•ฉ์‚ฐ PnL -34,618์› (๋ฐฑํ…Œ Optuna์™€ ์ˆซ์ž ๋‹ฌ๋ผ๋„ ์ •์ƒ โ€” ๊ณ ์ŠคํŠธยท์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑ ๊ฒฝ๋กœ ์ฐจ์ด). +- ์ด ๊ธฐ๊ฐ„ ๋ฐฑํ…Œ์—์„œ๋Š” **์œ ์˜๋ฏธํ•œ ํ†ต๊ณผ ์กฐํ•ฉ์ด ๊ฑฐ์˜ ์—†์—ˆ์Šต๋‹ˆ๋‹ค.** ์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑยท์†์ ˆยท์‹œ๊ฐ„์ฐฝ์„ ๋จผ์ € ์ ๊ฒ€ํ•˜์„ธ์š” (๋ŒํŒŒ 0๊ฑด์ด๋ฉด ํŠนํžˆ). + +## ์•ž์œผ๋กœ ์žฅ์—์„œ๋Š” +- **1~2์ผ Optuna best๋ฅผ ๋ฐ”๋กœ ์‹ค๋งค์— ๋„ฃ์ง€ ๋งˆ์„ธ์š”.** ๋‹ค์ผ(โ‰ฅ5๊ฑฐ๋ž˜์ผ) ์žฌ๊ฒ€์ฆยท์›น๋ฐฑํ…Œ 1ํšŒ ํ›„ ๊ฒ€ํ† . +- ์ ์šฉ ์‹œ์—๋Š” `results_gated` ํ›„๋ณด๋งŒ. ํƒ์ƒ‰์šฉ best(objective)์™€ ๋‹ค๋ฅผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. +- ์žฅ์ด ์ข์•„์ง€๊ฑฐ๋‚˜ ๋ณ€๋™์„ฑ์ด ์ปค์ง€๋ฉด: ์†์ ˆยทํŠธ๋ ˆ์ผยท์‹œ๊ฐ„์ฐฝ์ด ๋จผ์ € ๊นจ์ง‘๋‹ˆ๋‹ค. ์Šน๋ฅ  ์ž๋ž‘๋ณด๋‹ค **์†์ ˆ์ด ์‚ด์•„ ์žˆ๋Š”์ง€**๋ฅผ ๋ณด์„ธ์š”. +- ํ˜„์žฌ ์‚ฌํ›„ํ•ฉ๊ฒฉ 0๊ฑด โ†’ ํŒŒ๋ผ๋ฏธํ„ฐ ์œ ์ง€(ํ˜„ํ–‰ DB) + ์œ ๋‹ˆ๋ฒ„์Šค/๋ฐ์ดํ„ฐ ์ ๊ฒ€์ด ์šฐ์„ ์ž…๋‹ˆ๋‹ค. + +_์ƒ์„ฑ: 2026-09-04 20:13:45 (rule)_ + +## AI ์ฝ”๋ฉ˜ํŠธ (์ด์ „ ์žฅ / ์•ž์œผ๋กœ ์žฅ) [gemini] + +## ์ด์ „ ์žฅ์—์„œ๋Š” +๋‹จ์ผ ๊ฑฐ๋ž˜์ผ(2026-09-04) ๋ฐฑํ…Œ์ŠคํŠธ ๊ฒฐ๊ณผ, ์‚ฌํ›„ํ•ฉ๊ฒฉ ๋ฐ ์œ ํšจํ•œ ์ „๋žต ์กฐํ•ฉ์ด ์ „๋ฌดํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š” ํ‘œ๋ณธ ๋ถ€์กฑ๊ณผ 73%์˜ ๋†’์€ ๊ณผ์ ํ•ฉ ์œ„ํ—˜์„ ๋ช…ํ™•ํžˆ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค. ๋™๊ธฐ๊ฐ„ ์‹ค๋งค PnL ๋˜ํ•œ ๋งˆ์ด๋„ˆ์Šค๋ฅผ ๊ธฐ๋กํ•˜๋ฉฐ ๋ฐฑํ…Œ์ŠคํŠธ์™€์˜ ๊ดด๋ฆฌ๋ฅผ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ๊ฒฐ๊ณผ๋Š” ์šฐ์—ฐํ•œ ์Šน๋ฅ ์„ ๋ฐฐ์ œํ•˜๊ณ  ์‹ค๋งค ์ ์šฉ์— ์‹ ์ค‘ํ•ด์•ผ ํ•จ์„ ๊ฒฝ๊ณ ํ•ฉ๋‹ˆ๋‹ค. + +## ์•ž์œผ๋กœ ์žฅ์—์„œ๋Š” +ํ˜„ Optuna ๊ฒฐ๊ณผ๋ฅผ ์‹ค๋งค์— ์ ์šฉํ•˜๋Š” ๊ฒƒ์€ ์ ˆ๋Œ€ ๊ธˆ์ง€ํ•ฉ๋‹ˆ๋‹ค. ํ‘œ๋ณธ ๋ถ€์กฑ ๋ฐ ๋†’์€ ๊ณผ์ ํ•ฉ ์œ„ํ—˜์œผ๋กœ ์ธํ•ด, ํ˜„์žฌ๋Š” ๊ธฐ์กด DB๋ฅผ ์œ ์ง€ํ•˜๊ณ  ์œ ๋‹ˆ๋ฒ„์Šค, ํ‹ฑ ๋ฐ์ดํ„ฐ, ๊ทธ๋ฆฌ๊ณ  ๋ฐฑํ…Œ์ŠคํŠธ ๊ธฐ๊ฐ„์„ ์ตœ์†Œ 5๊ฑฐ๋ž˜์ผ ์ด์ƒ์œผ๋กœ ํ™•์žฅํ•˜์—ฌ ์žฌ๊ฒ€์ฆํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. โ€˜mode Top10 1์œ„โ€™๋Š” ๋‹จ์ˆœํžˆ ํƒ์ƒ‰ ์ค‘ ์šฐ์—ฐํžˆ ๋ฐœ์ƒํ•œ ์กฐํ•ฉ์ผ ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์ต์ ˆ ๋Œ€ํ‘œ๋กœ ๋‹จ์ •ํ•˜๊ฑฐ๋‚˜ ํ™•์ • ์ˆ˜์ต์„ ์•ฝ์†ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ์‹ค๋งค์™€ ๋ฐฑํ…Œ์ŠคํŠธ ๊ฐ„์˜ ๊ดด๋ฆฌ(๊ณ ์ŠคํŠธํผ์ง€)๋Š” ํ•ญ์ƒ ์กด์žฌํ•˜๋ฉฐ, ์†์ ˆ ๋ผ์ธ ์ž‘๋™ ์—ฌ๋ถ€ ํ™•์ธ ๋“ฑ ๋ฆฌ์Šคํฌ ๊ด€๋ฆฌ๊ฐ€ ์ตœ์šฐ์„ ์ž…๋‹ˆ๋‹ค. diff --git a/kis_trader/backtest/results/optuna_breakout_tpe_20260904_201541.briefing.md b/kis_trader/backtest/results/optuna_breakout_tpe_20260904_201541.briefing.md new file mode 100644 index 0000000..7689d82 --- /dev/null +++ b/kis_trader/backtest/results/optuna_breakout_tpe_20260904_201541.briefing.md @@ -0,0 +1,49 @@ +# Optuna ๋ธŒ๋ฆฌํ•‘ โ€” ๋ŒํŒŒ (tpe) +๊ธฐ๊ฐ„: 2026-09-04 ~ 2026-09-04 (๊ฑฐ๋ž˜์ผโ‰ˆ1์ผ) ยท trials 200/200 +ํƒ์ƒ‰ ๊ฒŒ์ดํŠธ: WRโ‰ฅ0% PFโ‰ฅ0 ยท min_tradesโ‰ฅ2 | ํ›„๋ณด ๊ฒŒ์ดํŠธ: WRโ‰ฅ40% PFโ‰ฅ1 ยท min_tradesโ‰ฅ2 +- min_trades=2: **ํ•ฉ๊ฒฉ ์ธ์ • ์ตœ์†Œ ๊ฑฐ๋ž˜ ๊ฑด์ˆ˜**(ํ‘œ๋ณธ ๋ถ€์กฑยท์šฐ์—ฐ ์Šน๋ฅ  ๋ฐฉ์ง€). ์ด๋ณด๋‹ค ์ ์€ ์กฐํ•ฉ์€ ํ•™์Šต/ํ›„๋ณด ์ง‘๊ณ„์—์„œ ์ œ์™ธ๋ฉ๋‹ˆ๋‹ค. +ํ•™์Šต์šฉ ํ†ต๊ณผ 0๊ฑด ยท ์‚ฌํ›„ํ•ฉ๊ฒฉ(results_gated) 0๊ฑด + +## ๊ณผ์ ํ•ฉยท์ ์šฉ ๊ฐ€๋Šฅ๋„ (ํœด๋ฆฌ์Šคํ‹ฑ) +- **๊ณผ์ ํ•ฉ ์œ„ํ—˜ 73.0%** ยท **์ ์šฉ ๊ฐ€๋Šฅ๋„ 27.0%** ยท ํŒ์ •: **๋น„๊ถŒ์žฅ** โ€” ๊ณผ์ ํ•ฉยทํ‘œ๋ณธ๋ถ€์กฑ ์œ„ํ—˜ ๋†’์Œ โ€” ์‹ค๋งค DB ์ฆ‰์‹œ ์ ์šฉ ๋น„๊ถŒ์žฅ + - ํ‘œ๋ณธ ์žฅ์ผ: +40.0p โ€” ๊ฑฐ๋ž˜์ผโ‰ˆ1์ผ โ€” ๋‹จ์ผ ์žฅ ๊ณผ์ ํ•ฉ ์œ„ํ—˜ ์ตœ๋Œ€ + - ๊ฑฐ๋ž˜ ํ‘œ๋ณธ: +25.0p โ€” ํ†ต๊ณผ ํ›„๋ณด ์—†์Œ โ€” ์ ์šฉ ๋ถˆ๊ฐ€ + - ์Šน๋ฅ ยทPF ์ด์ƒ์น˜: +0.0p โ€” ์ด์ƒ์น˜ ์—†์Œ + - ๊ฒŒ์ดํŠธ ์ปค๋ฒ„: +8.0p โ€” ํ•™์Šตยทgated ๋ชจ๋‘ ๋น„์–ด ์žˆ์Œ + - PnL ๊ณ ์›: +0.0p โ€” ๊ณ ์› ํŒ์ • ์Šคํ‚ต +- _์ฐธ๊ณ : ๊ณผ์ ํ•ฉ%๋Š” ๊ต์ฐจ๊ฒ€์ฆ ์ ์ˆ˜๊ฐ€ ์•„๋‹ˆ๋ผ ํ‘œ๋ณธยท์ด์ƒ์น˜ยท๊ณ ์› ํœด๋ฆฌ์Šคํ‹ฑ์ž…๋‹ˆ๋‹ค. ์ ์šฉ ๊ฐ€๋Šฅ๋„%=100โˆ’๊ณผ์ ํ•ฉ์œ„ํ—˜%. DB ์ ์šฉ ๋ฒ„ํŠผ ํ™œ์„ฑ ์กฐ๊ฑด(gated PnL>0)๊ณผ๋Š” ๋ณ„๊ฐœ์ž…๋‹ˆ๋‹ค._ + +## ์ตœ์ข… ์„ ํƒ ํ›„๋ณด (๊ทœ์น™ ยท DB ์ ์šฉ ์ „ ํ™•์ธ) +- ์•„๋ž˜๋Š” **์—ญํ• ์ด ๋‹ค๋ฅธ** 4์ข… ํ›„๋ณด์ž…๋‹ˆ๋‹ค. mode Top10 1์œ„ โ‰  ์ต์ ˆ ๋Œ€ํ‘œ ยท **DB 1์ˆœ์œ„๋Š” ์‚ฌํ›„ํ•ฉ๊ฒฉ(gated)** ์ž…๋‹ˆ๋‹ค. +- mode pool: `positive` ยท scoring: `band_proximity_p25_p75` + +### ํ›„๋ณด 4์ข… +- **โ‘  ์‚ฌํ›„ํ•ฉ๊ฒฉ 1์œ„ (apply: gated)**: ์—†์Œ +- **โ‘ก ์•ˆ์ • 1์œ„ (apply: stable)**: ์—†์Œ +- **โ‘ข mode_combo (apply: mode)**: ์—†์Œ (๋ฏธ์‚ฐ์ถœยท๊ตฌ JSON) +- **โ‘ฃ mode Top10 1์œ„ (apply: consensus ยท ๋ฐด๋“œ ์ „ํ˜• trial)**: ์—†์Œ +- mode Top10 meta: pool 0๊ฑด ยท ์ถ• 0๊ฐœ + +### ์ถ”์ฒœ (์ž๋™ ยท confirm ํ•„์ˆ˜) +1. **์‚ฌํ›„ํ•ฉ๊ฒฉ 0๊ฑด โ†’ DB ์ ์šฉ ๋น„๊ถŒ์žฅ.** ํ˜„ํ–‰ DB ์œ ์ง€ + ์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑยท๊ธฐ๊ฐ„ ์žฌ๊ฒ€์ฆ. +- โš  ์•ˆ์ • ๊ฒŒ์ดํŠธ 0๊ฑด โ†’ ์•ˆ์ • Top์€ **์ ์ˆ˜์ˆœ ํด๋ฐฑ** (์•ˆ์ • ๊ฒŒ์ดํŠธ 0๊ฑด โ†’ ํ•™์Šตํ’€ ์•ˆ์ •์ ์ˆ˜์ˆœ TopN (๋งˆ์ด๋„ˆ์Šค PnL ํฌํ•จ ยท ์ƒ๋Œ€๋น„๊ต)) + +## ์ด์ „ ์žฅ์—์„œ๋Š” +- ์‹ค๋งค ๋™๊ธฐ๊ฐ„ ์ฒญ์‚ฐ 13๊ฑด ยท ์Šน๋ฅ  31% ยท ํ•ฉ์‚ฐ PnL -34,618์› (๋ฐฑํ…Œ Optuna์™€ ์ˆซ์ž ๋‹ฌ๋ผ๋„ ์ •์ƒ โ€” ๊ณ ์ŠคํŠธยท์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑ ๊ฒฝ๋กœ ์ฐจ์ด). +- ์ด ๊ธฐ๊ฐ„ ๋ฐฑํ…Œ์—์„œ๋Š” **์œ ์˜๋ฏธํ•œ ํ†ต๊ณผ ์กฐํ•ฉ์ด ๊ฑฐ์˜ ์—†์—ˆ์Šต๋‹ˆ๋‹ค.** ์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑยท์†์ ˆยท์‹œ๊ฐ„์ฐฝ์„ ๋จผ์ € ์ ๊ฒ€ํ•˜์„ธ์š” (๋ŒํŒŒ 0๊ฑด์ด๋ฉด ํŠนํžˆ). + +## ์•ž์œผ๋กœ ์žฅ์—์„œ๋Š” +- **1~2์ผ Optuna best๋ฅผ ๋ฐ”๋กœ ์‹ค๋งค์— ๋„ฃ์ง€ ๋งˆ์„ธ์š”.** ๋‹ค์ผ(โ‰ฅ5๊ฑฐ๋ž˜์ผ) ์žฌ๊ฒ€์ฆยท์›น๋ฐฑํ…Œ 1ํšŒ ํ›„ ๊ฒ€ํ† . +- ์ ์šฉ ์‹œ์—๋Š” `results_gated` ํ›„๋ณด๋งŒ. ํƒ์ƒ‰์šฉ best(objective)์™€ ๋‹ค๋ฅผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. +- ์žฅ์ด ์ข์•„์ง€๊ฑฐ๋‚˜ ๋ณ€๋™์„ฑ์ด ์ปค์ง€๋ฉด: ์†์ ˆยทํŠธ๋ ˆ์ผยท์‹œ๊ฐ„์ฐฝ์ด ๋จผ์ € ๊นจ์ง‘๋‹ˆ๋‹ค. ์Šน๋ฅ  ์ž๋ž‘๋ณด๋‹ค **์†์ ˆ์ด ์‚ด์•„ ์žˆ๋Š”์ง€**๋ฅผ ๋ณด์„ธ์š”. +- ํ˜„์žฌ ์‚ฌํ›„ํ•ฉ๊ฒฉ 0๊ฑด โ†’ ํŒŒ๋ผ๋ฏธํ„ฐ ์œ ์ง€(ํ˜„ํ–‰ DB) + ์œ ๋‹ˆ๋ฒ„์Šค/๋ฐ์ดํ„ฐ ์ ๊ฒ€์ด ์šฐ์„ ์ž…๋‹ˆ๋‹ค. + +_์ƒ์„ฑ: 2026-09-04 20:15:41 (rule)_ + +## AI ์ฝ”๋ฉ˜ํŠธ (์ด์ „ ์žฅ / ์•ž์œผ๋กœ ์žฅ) [gemini] + +**์ด์ „ ์žฅ์—์„œ๋Š”** +์ง€๋‚œ 1์ผ ๋‹จ๊ธฐ ๋ฐฑํ…Œ์ŠคํŠธ๋Š” ์œ ํšจํ•œ ์ „๋žต ์กฐํ•ฉ์„ ์ „ํ˜€ ์ฐพ์ง€ ๋ชปํ–ˆ๊ณ , ๊ณผ์ ํ•ฉ ์œ„ํ—˜์ด 73%๋กœ ๋งค์šฐ ๋†’์Šต๋‹ˆ๋‹ค. ์ด๋Š” ํŠน์ • ๊ธฐ๊ฐ„์—๋งŒ ์šฐ์—ฐํžˆ ์ž‘๋™ํ•˜๋Š” ์กฐํ•ฉ์ผ ๊ฐ€๋Šฅ์„ฑ์ด ์ปค ์‹ค๋งค ์ ์šฉ ์‹œ ๋งค์šฐ ์œ„ํ—˜ํ•˜๋‹ค๋Š” ๋ช…๋ฐฑํ•œ ๊ฒฝ๊ณ ์ž…๋‹ˆ๋‹ค. ์‹ค์ œ ๋งค๋งค์—์„œ๋„ ๋ฐฑํ…Œ์ŠคํŠธ์™€ ๋‹ฌ๋ฆฌ ์ €์กฐํ•œ ์„ฑ๊ณผ๋ฅผ ๊ธฐ๋กํ•˜๋ฉฐ ์‹ค๋งค์™€ ๋ฐฑํ…Œ ๊ฐ„์˜ ๊ดด๋ฆฌ๋ฅผ ๋ณด์—ฌ์ฃผ์—ˆ์Šต๋‹ˆ๋‹ค. + +**์•ž์œผ๋กœ ์žฅ์—์„œ๋Š”** +ํ˜„์žฌ ๊ฒฐ๊ณผ๋Š” ๊ณผ์ ํ•ฉ ๋ฐ ํ‘œ๋ณธ ๋ถ€์กฑ ์œ„ํ—˜์ด ๋งค์šฐ ๋†’์•„ ์‹ค๋งค ์ ์šฉ์ด ๊ฐ•๋ ฅํžˆ ๋น„๊ถŒ์žฅ๋ฉ๋‹ˆ๋‹ค. DB 1์ˆœ์œ„์ด์ž ์‹ค์ œ ์ ์šฉ์— ์œ ์ผํ•˜๊ฒŒ ๊ถŒ์žฅ๋˜๋Š” '์‚ฌํ›„ํ•ฉ๊ฒฉ(gated)'๋œ ์กฐํ•ฉ์ด ์—†์œผ๋ฏ€๋กœ, **ํ˜„ํ–‰ DB๋ฅผ ์œ ์ง€ํ•˜๋ฉฐ ์œ ๋‹ˆ๋ฒ„์Šค, ํ‹ฑ ๋ฐ์ดํ„ฐ, ๊ธฐ๊ฐ„ ๋“ฑ์„ ์žฌ์ ๊ฒ€ํ•˜๋Š” ๊ฒƒ์ด ์šฐ์„ ์ž…๋‹ˆ๋‹ค.** 'mode Top10 1์œ„'๋Š” ์ต์ ˆ ๋Œ€ํ‘œ๊ฐ€ ์•„๋‹ˆ๋ฉฐ, ๋ฐฑํ…Œ์ŠคํŠธ ๊ฒฐ๊ณผ๊ฐ€ ์‹ค์ œ ๋งค๋งค์—์„œ ์žฌํ˜„๋˜์ง€ ์•Š๋Š” ๊ณ ์ŠคํŠธ ํผ์ง€ ๋“ฑ์˜ ๊ดด๋ฆฌ๊ฐ€ ์–ธ์ œ๋“  ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Œ์„ ํ•ญ์ƒ ์œ ๋…ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ํŠน์ • ์ข…๋ชฉ ๋งค์ˆ˜ ์ถ”์ฒœ์ด๋‚˜ ํ™•์ • ์ˆ˜์ต์€ ์ ˆ๋Œ€ ์•ฝ์†ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. diff --git a/kis_trader/backtest/results/optuna_breakout_tpe_20260905_011037.briefing.md b/kis_trader/backtest/results/optuna_breakout_tpe_20260905_011037.briefing.md new file mode 100644 index 0000000..c9ecc48 --- /dev/null +++ b/kis_trader/backtest/results/optuna_breakout_tpe_20260905_011037.briefing.md @@ -0,0 +1,49 @@ +# Optuna ๋ธŒ๋ฆฌํ•‘ โ€” ๋ŒํŒŒ (tpe) +๊ธฐ๊ฐ„: 2026-09-04 ~ 2026-09-04 (๊ฑฐ๋ž˜์ผโ‰ˆ1์ผ) ยท trials 200/200 +ํƒ์ƒ‰ ๊ฒŒ์ดํŠธ: WRโ‰ฅ0% PFโ‰ฅ0 ยท min_tradesโ‰ฅ2 | ํ›„๋ณด ๊ฒŒ์ดํŠธ: WRโ‰ฅ40% PFโ‰ฅ1 ยท min_tradesโ‰ฅ2 +- min_trades=2: **ํ•ฉ๊ฒฉ ์ธ์ • ์ตœ์†Œ ๊ฑฐ๋ž˜ ๊ฑด์ˆ˜**(ํ‘œ๋ณธ ๋ถ€์กฑยท์šฐ์—ฐ ์Šน๋ฅ  ๋ฐฉ์ง€). ์ด๋ณด๋‹ค ์ ์€ ์กฐํ•ฉ์€ ํ•™์Šต/ํ›„๋ณด ์ง‘๊ณ„์—์„œ ์ œ์™ธ๋ฉ๋‹ˆ๋‹ค. +ํ•™์Šต์šฉ ํ†ต๊ณผ 0๊ฑด ยท ์‚ฌํ›„ํ•ฉ๊ฒฉ(results_gated) 0๊ฑด + +## ๊ณผ์ ํ•ฉยท์ ์šฉ ๊ฐ€๋Šฅ๋„ (ํœด๋ฆฌ์Šคํ‹ฑ) +- **๊ณผ์ ํ•ฉ ์œ„ํ—˜ 73.0%** ยท **์ ์šฉ ๊ฐ€๋Šฅ๋„ 27.0%** ยท ํŒ์ •: **๋น„๊ถŒ์žฅ** โ€” ๊ณผ์ ํ•ฉยทํ‘œ๋ณธ๋ถ€์กฑ ์œ„ํ—˜ ๋†’์Œ โ€” ์‹ค๋งค DB ์ฆ‰์‹œ ์ ์šฉ ๋น„๊ถŒ์žฅ + - ํ‘œ๋ณธ ์žฅ์ผ: +40.0p โ€” ๊ฑฐ๋ž˜์ผโ‰ˆ1์ผ โ€” ๋‹จ์ผ ์žฅ ๊ณผ์ ํ•ฉ ์œ„ํ—˜ ์ตœ๋Œ€ + - ๊ฑฐ๋ž˜ ํ‘œ๋ณธ: +25.0p โ€” ํ†ต๊ณผ ํ›„๋ณด ์—†์Œ โ€” ์ ์šฉ ๋ถˆ๊ฐ€ + - ์Šน๋ฅ ยทPF ์ด์ƒ์น˜: +0.0p โ€” ์ด์ƒ์น˜ ์—†์Œ + - ๊ฒŒ์ดํŠธ ์ปค๋ฒ„: +8.0p โ€” ํ•™์Šตยทgated ๋ชจ๋‘ ๋น„์–ด ์žˆ์Œ + - PnL ๊ณ ์›: +0.0p โ€” ๊ณ ์› ํŒ์ • ์Šคํ‚ต +- _์ฐธ๊ณ : ๊ณผ์ ํ•ฉ%๋Š” ๊ต์ฐจ๊ฒ€์ฆ ์ ์ˆ˜๊ฐ€ ์•„๋‹ˆ๋ผ ํ‘œ๋ณธยท์ด์ƒ์น˜ยท๊ณ ์› ํœด๋ฆฌ์Šคํ‹ฑ์ž…๋‹ˆ๋‹ค. ์ ์šฉ ๊ฐ€๋Šฅ๋„%=100โˆ’๊ณผ์ ํ•ฉ์œ„ํ—˜%. DB ์ ์šฉ ๋ฒ„ํŠผ ํ™œ์„ฑ ์กฐ๊ฑด(gated PnL>0)๊ณผ๋Š” ๋ณ„๊ฐœ์ž…๋‹ˆ๋‹ค._ + +## ์ตœ์ข… ์„ ํƒ ํ›„๋ณด (๊ทœ์น™ ยท DB ์ ์šฉ ์ „ ํ™•์ธ) +- ์•„๋ž˜๋Š” **์—ญํ• ์ด ๋‹ค๋ฅธ** 4์ข… ํ›„๋ณด์ž…๋‹ˆ๋‹ค. mode Top10 1์œ„ โ‰  ์ต์ ˆ ๋Œ€ํ‘œ ยท **DB 1์ˆœ์œ„๋Š” ์‚ฌํ›„ํ•ฉ๊ฒฉ(gated)** ์ž…๋‹ˆ๋‹ค. +- mode pool: `positive` ยท scoring: `band_proximity_p25_p75` + +### ํ›„๋ณด 4์ข… +- **โ‘  ์‚ฌํ›„ํ•ฉ๊ฒฉ 1์œ„ (apply: gated)**: ์—†์Œ +- **โ‘ก ์•ˆ์ • 1์œ„ (apply: stable)**: ์—†์Œ +- **โ‘ข mode_combo (apply: mode)**: ์—†์Œ (๋ฏธ์‚ฐ์ถœยท๊ตฌ JSON) +- **โ‘ฃ mode Top10 1์œ„ (apply: consensus ยท ๋ฐด๋“œ ์ „ํ˜• trial)**: ์—†์Œ +- mode Top10 meta: pool 0๊ฑด ยท ์ถ• 0๊ฐœ + +### ์ถ”์ฒœ (์ž๋™ ยท confirm ํ•„์ˆ˜) +1. **์‚ฌํ›„ํ•ฉ๊ฒฉ 0๊ฑด โ†’ DB ์ ์šฉ ๋น„๊ถŒ์žฅ.** ํ˜„ํ–‰ DB ์œ ์ง€ + ์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑยท๊ธฐ๊ฐ„ ์žฌ๊ฒ€์ฆ. +- โš  ์•ˆ์ • ๊ฒŒ์ดํŠธ 0๊ฑด โ†’ ์•ˆ์ • Top์€ **์ ์ˆ˜์ˆœ ํด๋ฐฑ** (์•ˆ์ • ๊ฒŒ์ดํŠธ 0๊ฑด โ†’ ํ•™์Šตํ’€ ์•ˆ์ •์ ์ˆ˜์ˆœ TopN (๋งˆ์ด๋„ˆ์Šค PnL ํฌํ•จ ยท ์ƒ๋Œ€๋น„๊ต)) + +## ์ด์ „ ์žฅ์—์„œ๋Š” +- ์‹ค๋งค ๋™๊ธฐ๊ฐ„ ์ฒญ์‚ฐ 13๊ฑด ยท ์Šน๋ฅ  31% ยท ํ•ฉ์‚ฐ PnL -34,618์› (๋ฐฑํ…Œ Optuna์™€ ์ˆซ์ž ๋‹ฌ๋ผ๋„ ์ •์ƒ โ€” ๊ณ ์ŠคํŠธยท์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑ ๊ฒฝ๋กœ ์ฐจ์ด). +- ์ด ๊ธฐ๊ฐ„ ๋ฐฑํ…Œ์—์„œ๋Š” **์œ ์˜๋ฏธํ•œ ํ†ต๊ณผ ์กฐํ•ฉ์ด ๊ฑฐ์˜ ์—†์—ˆ์Šต๋‹ˆ๋‹ค.** ์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑยท์†์ ˆยท์‹œ๊ฐ„์ฐฝ์„ ๋จผ์ € ์ ๊ฒ€ํ•˜์„ธ์š” (๋ŒํŒŒ 0๊ฑด์ด๋ฉด ํŠนํžˆ). + +## ์•ž์œผ๋กœ ์žฅ์—์„œ๋Š” +- **1~2์ผ Optuna best๋ฅผ ๋ฐ”๋กœ ์‹ค๋งค์— ๋„ฃ์ง€ ๋งˆ์„ธ์š”.** ๋‹ค์ผ(โ‰ฅ5๊ฑฐ๋ž˜์ผ) ์žฌ๊ฒ€์ฆยท์›น๋ฐฑํ…Œ 1ํšŒ ํ›„ ๊ฒ€ํ† . +- ์ ์šฉ ์‹œ์—๋Š” `results_gated` ํ›„๋ณด๋งŒ. ํƒ์ƒ‰์šฉ best(objective)์™€ ๋‹ค๋ฅผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. +- ์žฅ์ด ์ข์•„์ง€๊ฑฐ๋‚˜ ๋ณ€๋™์„ฑ์ด ์ปค์ง€๋ฉด: ์†์ ˆยทํŠธ๋ ˆ์ผยท์‹œ๊ฐ„์ฐฝ์ด ๋จผ์ € ๊นจ์ง‘๋‹ˆ๋‹ค. ์Šน๋ฅ  ์ž๋ž‘๋ณด๋‹ค **์†์ ˆ์ด ์‚ด์•„ ์žˆ๋Š”์ง€**๋ฅผ ๋ณด์„ธ์š”. +- ํ˜„์žฌ ์‚ฌํ›„ํ•ฉ๊ฒฉ 0๊ฑด โ†’ ํŒŒ๋ผ๋ฏธํ„ฐ ์œ ์ง€(ํ˜„ํ–‰ DB) + ์œ ๋‹ˆ๋ฒ„์Šค/๋ฐ์ดํ„ฐ ์ ๊ฒ€์ด ์šฐ์„ ์ž…๋‹ˆ๋‹ค. + +_์ƒ์„ฑ: 2026-09-05 01:10:37 (rule)_ + +## AI ์ฝ”๋ฉ˜ํŠธ (์ด์ „ ์žฅ / ์•ž์œผ๋กœ ์žฅ) [gemini] + +**์ด์ „ ์žฅ์—์„œ๋Š”** +์ด์ „ ๊ธฐ๊ฐ„ ์‹ค๋งค๋Š” 13๊ฑด ์ค‘ 31% ์Šน๋ฅ ๋กœ -34,618์› ์†์‹ค์„ ๊ธฐ๋กํ–ˆ์Šต๋‹ˆ๋‹ค. ๋ฐฑํ…Œ์ŠคํŠธ Optuna ๊ฒฐ๊ณผ ์—ญ์‹œ ๋‹จ ํ•˜๋ฃจ์˜ ๊ฑฐ๋ž˜์ผ ๋ถ„์„์œผ๋กœ ๊ณผ์ ํ•ฉ ์œ„ํ—˜ 73%, ์ ์šฉ ๊ฐ€๋Šฅ๋„ 27%๋กœ '๋น„๊ถŒ์žฅ' ํŒ์ •์„ ๋ฐ›์•˜์Šต๋‹ˆ๋‹ค. ์œ ์˜๋ฏธํ•œ ์‚ฌํ›„ํ•ฉ๊ฒฉ(gated) ์กฐํ•ฉ์ด ์ „๋ฌดํ•˜๋ฉฐ, ํ‘œ๋ณธ ๋ถ€์กฑ๊ณผ ์‹ค๋งค-๋ฐฑํ…Œ ๊ดด๋ฆฌ ์œ„ํ—˜์ด ๋งค์šฐ ๋†’์Šต๋‹ˆ๋‹ค. + +**์•ž์œผ๋กœ ์žฅ์—์„œ๋Š”** +๋‹จ์ผ ๊ฑฐ๋ž˜์ผ Optuna ๊ฒฐ๊ณผ๋Š” ๊ณผ์ ํ•ฉ ์œ„ํ—˜์ด ์ปค ์‹ค๋งค์— ์ฆ‰์‹œ ์ ์šฉ ๋ถˆ๊ฐ€ํ•ฉ๋‹ˆ๋‹ค. DB 1์ˆœ์œ„์ธ ์‚ฌํ›„ํ•ฉ๊ฒฉ(gated)์ด 0๊ฑด์ด๋ฏ€๋กœ, ํ˜„ํ–‰ ํŒŒ๋ผ๋ฏธํ„ฐ ์œ ์ง€ ๋ฐ ์œ ๋‹ˆ๋ฒ„์Šคยท๋ฐ์ดํ„ฐ ์žฌ๊ฒ€์ฆ์ด ์šฐ์„ ์ž…๋‹ˆ๋‹ค. `mode Top10 1์œ„`๋ฅผ ์ต์ ˆ ๋Œ€ํ‘œ๋กœ ๋‹จ์ •ํ•ด์„  ์•ˆ ๋ฉ๋‹ˆ๋‹ค. ๋ฐฑํ…Œ์ŠคํŠธ ๊ฒฐ๊ณผ์™€ ์‹ค์ œ๋Š” ๊ดด๋ฆฌ๊ฐ€ ํฌ๋ฉฐ(๊ณ ์ŠคํŠธํผ์ง€ ๋“ฑ), ํ™•์ • ์ˆ˜์ต์„ ์•ฝ์†๋“œ๋ฆด ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. diff --git a/kis_trader/backtest/results/optuna_breakout_tpe_20260905_011144.briefing.md b/kis_trader/backtest/results/optuna_breakout_tpe_20260905_011144.briefing.md new file mode 100644 index 0000000..87a25f0 --- /dev/null +++ b/kis_trader/backtest/results/optuna_breakout_tpe_20260905_011144.briefing.md @@ -0,0 +1,49 @@ +# Optuna ๋ธŒ๋ฆฌํ•‘ โ€” ๋ŒํŒŒ (tpe) +๊ธฐ๊ฐ„: 2026-09-04 ~ 2026-09-04 (๊ฑฐ๋ž˜์ผโ‰ˆ1์ผ) ยท trials 200/200 +ํƒ์ƒ‰ ๊ฒŒ์ดํŠธ: WRโ‰ฅ0% PFโ‰ฅ0 ยท min_tradesโ‰ฅ2 | ํ›„๋ณด ๊ฒŒ์ดํŠธ: WRโ‰ฅ40% PFโ‰ฅ1 ยท min_tradesโ‰ฅ2 +- min_trades=2: **ํ•ฉ๊ฒฉ ์ธ์ • ์ตœ์†Œ ๊ฑฐ๋ž˜ ๊ฑด์ˆ˜**(ํ‘œ๋ณธ ๋ถ€์กฑยท์šฐ์—ฐ ์Šน๋ฅ  ๋ฐฉ์ง€). ์ด๋ณด๋‹ค ์ ์€ ์กฐํ•ฉ์€ ํ•™์Šต/ํ›„๋ณด ์ง‘๊ณ„์—์„œ ์ œ์™ธ๋ฉ๋‹ˆ๋‹ค. +ํ•™์Šต์šฉ ํ†ต๊ณผ 0๊ฑด ยท ์‚ฌํ›„ํ•ฉ๊ฒฉ(results_gated) 0๊ฑด + +## ๊ณผ์ ํ•ฉยท์ ์šฉ ๊ฐ€๋Šฅ๋„ (ํœด๋ฆฌ์Šคํ‹ฑ) +- **๊ณผ์ ํ•ฉ ์œ„ํ—˜ 73.0%** ยท **์ ์šฉ ๊ฐ€๋Šฅ๋„ 27.0%** ยท ํŒ์ •: **๋น„๊ถŒ์žฅ** โ€” ๊ณผ์ ํ•ฉยทํ‘œ๋ณธ๋ถ€์กฑ ์œ„ํ—˜ ๋†’์Œ โ€” ์‹ค๋งค DB ์ฆ‰์‹œ ์ ์šฉ ๋น„๊ถŒ์žฅ + - ํ‘œ๋ณธ ์žฅ์ผ: +40.0p โ€” ๊ฑฐ๋ž˜์ผโ‰ˆ1์ผ โ€” ๋‹จ์ผ ์žฅ ๊ณผ์ ํ•ฉ ์œ„ํ—˜ ์ตœ๋Œ€ + - ๊ฑฐ๋ž˜ ํ‘œ๋ณธ: +25.0p โ€” ํ†ต๊ณผ ํ›„๋ณด ์—†์Œ โ€” ์ ์šฉ ๋ถˆ๊ฐ€ + - ์Šน๋ฅ ยทPF ์ด์ƒ์น˜: +0.0p โ€” ์ด์ƒ์น˜ ์—†์Œ + - ๊ฒŒ์ดํŠธ ์ปค๋ฒ„: +8.0p โ€” ํ•™์Šตยทgated ๋ชจ๋‘ ๋น„์–ด ์žˆ์Œ + - PnL ๊ณ ์›: +0.0p โ€” ๊ณ ์› ํŒ์ • ์Šคํ‚ต +- _์ฐธ๊ณ : ๊ณผ์ ํ•ฉ%๋Š” ๊ต์ฐจ๊ฒ€์ฆ ์ ์ˆ˜๊ฐ€ ์•„๋‹ˆ๋ผ ํ‘œ๋ณธยท์ด์ƒ์น˜ยท๊ณ ์› ํœด๋ฆฌ์Šคํ‹ฑ์ž…๋‹ˆ๋‹ค. ์ ์šฉ ๊ฐ€๋Šฅ๋„%=100โˆ’๊ณผ์ ํ•ฉ์œ„ํ—˜%. DB ์ ์šฉ ๋ฒ„ํŠผ ํ™œ์„ฑ ์กฐ๊ฑด(gated PnL>0)๊ณผ๋Š” ๋ณ„๊ฐœ์ž…๋‹ˆ๋‹ค._ + +## ์ตœ์ข… ์„ ํƒ ํ›„๋ณด (๊ทœ์น™ ยท DB ์ ์šฉ ์ „ ํ™•์ธ) +- ์•„๋ž˜๋Š” **์—ญํ• ์ด ๋‹ค๋ฅธ** 4์ข… ํ›„๋ณด์ž…๋‹ˆ๋‹ค. mode Top10 1์œ„ โ‰  ์ต์ ˆ ๋Œ€ํ‘œ ยท **DB 1์ˆœ์œ„๋Š” ์‚ฌํ›„ํ•ฉ๊ฒฉ(gated)** ์ž…๋‹ˆ๋‹ค. +- mode pool: `positive` ยท scoring: `band_proximity_p25_p75` + +### ํ›„๋ณด 4์ข… +- **โ‘  ์‚ฌํ›„ํ•ฉ๊ฒฉ 1์œ„ (apply: gated)**: ์—†์Œ +- **โ‘ก ์•ˆ์ • 1์œ„ (apply: stable)**: ์—†์Œ +- **โ‘ข mode_combo (apply: mode)**: ์—†์Œ (๋ฏธ์‚ฐ์ถœยท๊ตฌ JSON) +- **โ‘ฃ mode Top10 1์œ„ (apply: consensus ยท ๋ฐด๋“œ ์ „ํ˜• trial)**: ์—†์Œ +- mode Top10 meta: pool 0๊ฑด ยท ์ถ• 0๊ฐœ + +### ์ถ”์ฒœ (์ž๋™ ยท confirm ํ•„์ˆ˜) +1. **์‚ฌํ›„ํ•ฉ๊ฒฉ 0๊ฑด โ†’ DB ์ ์šฉ ๋น„๊ถŒ์žฅ.** ํ˜„ํ–‰ DB ์œ ์ง€ + ์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑยท๊ธฐ๊ฐ„ ์žฌ๊ฒ€์ฆ. +- โš  ์•ˆ์ • ๊ฒŒ์ดํŠธ 0๊ฑด โ†’ ์•ˆ์ • Top์€ **์ ์ˆ˜์ˆœ ํด๋ฐฑ** (์•ˆ์ • ๊ฒŒ์ดํŠธ 0๊ฑด โ†’ ํ•™์Šตํ’€ ์•ˆ์ •์ ์ˆ˜์ˆœ TopN (๋งˆ์ด๋„ˆ์Šค PnL ํฌํ•จ ยท ์ƒ๋Œ€๋น„๊ต)) + +## ์ด์ „ ์žฅ์—์„œ๋Š” +- ์‹ค๋งค ๋™๊ธฐ๊ฐ„ ์ฒญ์‚ฐ 13๊ฑด ยท ์Šน๋ฅ  31% ยท ํ•ฉ์‚ฐ PnL -34,618์› (๋ฐฑํ…Œ Optuna์™€ ์ˆซ์ž ๋‹ฌ๋ผ๋„ ์ •์ƒ โ€” ๊ณ ์ŠคํŠธยท์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑ ๊ฒฝ๋กœ ์ฐจ์ด). +- ์ด ๊ธฐ๊ฐ„ ๋ฐฑํ…Œ์—์„œ๋Š” **์œ ์˜๋ฏธํ•œ ํ†ต๊ณผ ์กฐํ•ฉ์ด ๊ฑฐ์˜ ์—†์—ˆ์Šต๋‹ˆ๋‹ค.** ์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑยท์†์ ˆยท์‹œ๊ฐ„์ฐฝ์„ ๋จผ์ € ์ ๊ฒ€ํ•˜์„ธ์š” (๋ŒํŒŒ 0๊ฑด์ด๋ฉด ํŠนํžˆ). + +## ์•ž์œผ๋กœ ์žฅ์—์„œ๋Š” +- **1~2์ผ Optuna best๋ฅผ ๋ฐ”๋กœ ์‹ค๋งค์— ๋„ฃ์ง€ ๋งˆ์„ธ์š”.** ๋‹ค์ผ(โ‰ฅ5๊ฑฐ๋ž˜์ผ) ์žฌ๊ฒ€์ฆยท์›น๋ฐฑํ…Œ 1ํšŒ ํ›„ ๊ฒ€ํ† . +- ์ ์šฉ ์‹œ์—๋Š” `results_gated` ํ›„๋ณด๋งŒ. ํƒ์ƒ‰์šฉ best(objective)์™€ ๋‹ค๋ฅผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. +- ์žฅ์ด ์ข์•„์ง€๊ฑฐ๋‚˜ ๋ณ€๋™์„ฑ์ด ์ปค์ง€๋ฉด: ์†์ ˆยทํŠธ๋ ˆ์ผยท์‹œ๊ฐ„์ฐฝ์ด ๋จผ์ € ๊นจ์ง‘๋‹ˆ๋‹ค. ์Šน๋ฅ  ์ž๋ž‘๋ณด๋‹ค **์†์ ˆ์ด ์‚ด์•„ ์žˆ๋Š”์ง€**๋ฅผ ๋ณด์„ธ์š”. +- ํ˜„์žฌ ์‚ฌํ›„ํ•ฉ๊ฒฉ 0๊ฑด โ†’ ํŒŒ๋ผ๋ฏธํ„ฐ ์œ ์ง€(ํ˜„ํ–‰ DB) + ์œ ๋‹ˆ๋ฒ„์Šค/๋ฐ์ดํ„ฐ ์ ๊ฒ€์ด ์šฐ์„ ์ž…๋‹ˆ๋‹ค. + +_์ƒ์„ฑ: 2026-09-05 01:11:44 (rule)_ + +## AI ์ฝ”๋ฉ˜ํŠธ (์ด์ „ ์žฅ / ์•ž์œผ๋กœ ์žฅ) [gemini] + +**์ด์ „ ์žฅ์—์„œ๋Š”** +๋‹จ 1์ผ๊ฐ„์˜ ์งง์€ ๋ฐฑํ…Œ์ŠคํŠธ ๊ธฐ๊ฐ„์œผ๋กœ ์ธํ•ด ๊ณผ์ ํ•ฉ ์œ„ํ—˜์ด 73%์— ๋‹ฌํ•˜๋ฉฐ, ์œ ์˜๋ฏธํ•œ ์‚ฌํ›„ํ•ฉ๊ฒฉ(gated) ์ „๋žต ํ›„๋ณด๊ฐ€ ์ „ํ˜€ ๋„์ถœ๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. ์ด๋Š” ๊ทน์‹ฌํ•œ ํ‘œ๋ณธ ๋ถ€์กฑ์„ ์˜๋ฏธํ•˜๋ฉฐ, ๋ฐฑํ…Œ์ŠคํŠธ ๊ฒฐ๊ณผ์™€ ์‹ค์ œ ๋งค๋งค ๊ฐ„์˜ ๊ดด๋ฆฌ(๊ณ ์ŠคํŠธํผ์ง€ ๋“ฑ)๊ฐ€ ๋งค์šฐ ํด ์ˆ˜ ์žˆ์Œ์„ ๋ถ„๋ช…ํžˆ ๊ฒฝ๊ณ ํ•ฉ๋‹ˆ๋‹ค. + +**์•ž์œผ๋กœ ์žฅ์—์„œ๋Š”** +๊ธˆ๋ฒˆ 1์ผ Optuna ๊ฒฐ๊ณผ๋Š” ์‹ค๋งค ์ ์šฉ์ด ใ€Œ๋น„๊ถŒ์žฅใ€๋ฉ๋‹ˆ๋‹ค. ใ€Œ์‚ฌํ›„ํ•ฉ๊ฒฉ(gated)ใ€๋œ ์ „๋žต์ด 0๊ฑด์ด๋ฏ€๋กœ, Mode Top10 1์œ„๋ฅผ ํฌํ•จํ•œ ์–ด๋–ค ํ›„๋ณด๋„ ์ต์ ˆ ๋Œ€ํ‘œ๋กœ ๋‹จ์ •ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ํ˜„ํ–‰ DB๋ฅผ ์œ ์ง€ํ•˜๊ณ , ์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑ ๋ฐ์ดํ„ฐยท๊ธฐ๊ฐ„ ์„ค์ • ๋“ฑ ๊ทผ๋ณธ์ ์ธ ์žฌ๊ฒ€์ฆ์ด ์„ ํ–‰๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ตœ์†Œ 5๊ฑฐ๋ž˜์ผ ์ด์ƒ ๋‹ค์ผ ๊ฒ€์ฆ ์—†์ด๋Š” ์‹ค๋งค ์ ์šฉ์„ ์‚ผ๊ฐ€์‹ญ์‹œ์˜ค. diff --git a/kis_trader/backtest/results/optuna_breakout_tpe_20260905_011324.briefing.md b/kis_trader/backtest/results/optuna_breakout_tpe_20260905_011324.briefing.md new file mode 100644 index 0000000..6395abb --- /dev/null +++ b/kis_trader/backtest/results/optuna_breakout_tpe_20260905_011324.briefing.md @@ -0,0 +1,49 @@ +# Optuna ๋ธŒ๋ฆฌํ•‘ โ€” ๋ŒํŒŒ (tpe) +๊ธฐ๊ฐ„: 2026-09-04 ~ 2026-09-04 (๊ฑฐ๋ž˜์ผโ‰ˆ1์ผ) ยท trials 200/200 +ํƒ์ƒ‰ ๊ฒŒ์ดํŠธ: WRโ‰ฅ0% PFโ‰ฅ0 ยท min_tradesโ‰ฅ2 | ํ›„๋ณด ๊ฒŒ์ดํŠธ: WRโ‰ฅ40% PFโ‰ฅ1 ยท min_tradesโ‰ฅ2 +- min_trades=2: **ํ•ฉ๊ฒฉ ์ธ์ • ์ตœ์†Œ ๊ฑฐ๋ž˜ ๊ฑด์ˆ˜**(ํ‘œ๋ณธ ๋ถ€์กฑยท์šฐ์—ฐ ์Šน๋ฅ  ๋ฐฉ์ง€). ์ด๋ณด๋‹ค ์ ์€ ์กฐํ•ฉ์€ ํ•™์Šต/ํ›„๋ณด ์ง‘๊ณ„์—์„œ ์ œ์™ธ๋ฉ๋‹ˆ๋‹ค. +ํ•™์Šต์šฉ ํ†ต๊ณผ 0๊ฑด ยท ์‚ฌํ›„ํ•ฉ๊ฒฉ(results_gated) 0๊ฑด + +## ๊ณผ์ ํ•ฉยท์ ์šฉ ๊ฐ€๋Šฅ๋„ (ํœด๋ฆฌ์Šคํ‹ฑ) +- **๊ณผ์ ํ•ฉ ์œ„ํ—˜ 73.0%** ยท **์ ์šฉ ๊ฐ€๋Šฅ๋„ 27.0%** ยท ํŒ์ •: **๋น„๊ถŒ์žฅ** โ€” ๊ณผ์ ํ•ฉยทํ‘œ๋ณธ๋ถ€์กฑ ์œ„ํ—˜ ๋†’์Œ โ€” ์‹ค๋งค DB ์ฆ‰์‹œ ์ ์šฉ ๋น„๊ถŒ์žฅ + - ํ‘œ๋ณธ ์žฅ์ผ: +40.0p โ€” ๊ฑฐ๋ž˜์ผโ‰ˆ1์ผ โ€” ๋‹จ์ผ ์žฅ ๊ณผ์ ํ•ฉ ์œ„ํ—˜ ์ตœ๋Œ€ + - ๊ฑฐ๋ž˜ ํ‘œ๋ณธ: +25.0p โ€” ํ†ต๊ณผ ํ›„๋ณด ์—†์Œ โ€” ์ ์šฉ ๋ถˆ๊ฐ€ + - ์Šน๋ฅ ยทPF ์ด์ƒ์น˜: +0.0p โ€” ์ด์ƒ์น˜ ์—†์Œ + - ๊ฒŒ์ดํŠธ ์ปค๋ฒ„: +8.0p โ€” ํ•™์Šตยทgated ๋ชจ๋‘ ๋น„์–ด ์žˆ์Œ + - PnL ๊ณ ์›: +0.0p โ€” ๊ณ ์› ํŒ์ • ์Šคํ‚ต +- _์ฐธ๊ณ : ๊ณผ์ ํ•ฉ%๋Š” ๊ต์ฐจ๊ฒ€์ฆ ์ ์ˆ˜๊ฐ€ ์•„๋‹ˆ๋ผ ํ‘œ๋ณธยท์ด์ƒ์น˜ยท๊ณ ์› ํœด๋ฆฌ์Šคํ‹ฑ์ž…๋‹ˆ๋‹ค. ์ ์šฉ ๊ฐ€๋Šฅ๋„%=100โˆ’๊ณผ์ ํ•ฉ์œ„ํ—˜%. DB ์ ์šฉ ๋ฒ„ํŠผ ํ™œ์„ฑ ์กฐ๊ฑด(gated PnL>0)๊ณผ๋Š” ๋ณ„๊ฐœ์ž…๋‹ˆ๋‹ค._ + +## ์ตœ์ข… ์„ ํƒ ํ›„๋ณด (๊ทœ์น™ ยท DB ์ ์šฉ ์ „ ํ™•์ธ) +- ์•„๋ž˜๋Š” **์—ญํ• ์ด ๋‹ค๋ฅธ** 4์ข… ํ›„๋ณด์ž…๋‹ˆ๋‹ค. mode Top10 1์œ„ โ‰  ์ต์ ˆ ๋Œ€ํ‘œ ยท **DB 1์ˆœ์œ„๋Š” ์‚ฌํ›„ํ•ฉ๊ฒฉ(gated)** ์ž…๋‹ˆ๋‹ค. +- mode pool: `positive` ยท scoring: `band_proximity_p25_p75` + +### ํ›„๋ณด 4์ข… +- **โ‘  ์‚ฌํ›„ํ•ฉ๊ฒฉ 1์œ„ (apply: gated)**: ์—†์Œ +- **โ‘ก ์•ˆ์ • 1์œ„ (apply: stable)**: ์—†์Œ +- **โ‘ข mode_combo (apply: mode)**: ์—†์Œ (๋ฏธ์‚ฐ์ถœยท๊ตฌ JSON) +- **โ‘ฃ mode Top10 1์œ„ (apply: consensus ยท ๋ฐด๋“œ ์ „ํ˜• trial)**: ์—†์Œ +- mode Top10 meta: pool 0๊ฑด ยท ์ถ• 0๊ฐœ + +### ์ถ”์ฒœ (์ž๋™ ยท confirm ํ•„์ˆ˜) +1. **์‚ฌํ›„ํ•ฉ๊ฒฉ 0๊ฑด โ†’ DB ์ ์šฉ ๋น„๊ถŒ์žฅ.** ํ˜„ํ–‰ DB ์œ ์ง€ + ์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑยท๊ธฐ๊ฐ„ ์žฌ๊ฒ€์ฆ. +- โš  ์•ˆ์ • ๊ฒŒ์ดํŠธ 0๊ฑด โ†’ ์•ˆ์ • Top์€ **์ ์ˆ˜์ˆœ ํด๋ฐฑ** (์•ˆ์ • ๊ฒŒ์ดํŠธ 0๊ฑด โ†’ ํ•™์Šตํ’€ ์•ˆ์ •์ ์ˆ˜์ˆœ TopN (๋งˆ์ด๋„ˆ์Šค PnL ํฌํ•จ ยท ์ƒ๋Œ€๋น„๊ต)) + +## ์ด์ „ ์žฅ์—์„œ๋Š” +- ์‹ค๋งค ๋™๊ธฐ๊ฐ„ ์ฒญ์‚ฐ 13๊ฑด ยท ์Šน๋ฅ  31% ยท ํ•ฉ์‚ฐ PnL -34,618์› (๋ฐฑํ…Œ Optuna์™€ ์ˆซ์ž ๋‹ฌ๋ผ๋„ ์ •์ƒ โ€” ๊ณ ์ŠคํŠธยท์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑ ๊ฒฝ๋กœ ์ฐจ์ด). +- ์ด ๊ธฐ๊ฐ„ ๋ฐฑํ…Œ์—์„œ๋Š” **์œ ์˜๋ฏธํ•œ ํ†ต๊ณผ ์กฐํ•ฉ์ด ๊ฑฐ์˜ ์—†์—ˆ์Šต๋‹ˆ๋‹ค.** ์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑยท์†์ ˆยท์‹œ๊ฐ„์ฐฝ์„ ๋จผ์ € ์ ๊ฒ€ํ•˜์„ธ์š” (๋ŒํŒŒ 0๊ฑด์ด๋ฉด ํŠนํžˆ). + +## ์•ž์œผ๋กœ ์žฅ์—์„œ๋Š” +- **1~2์ผ Optuna best๋ฅผ ๋ฐ”๋กœ ์‹ค๋งค์— ๋„ฃ์ง€ ๋งˆ์„ธ์š”.** ๋‹ค์ผ(โ‰ฅ5๊ฑฐ๋ž˜์ผ) ์žฌ๊ฒ€์ฆยท์›น๋ฐฑํ…Œ 1ํšŒ ํ›„ ๊ฒ€ํ† . +- ์ ์šฉ ์‹œ์—๋Š” `results_gated` ํ›„๋ณด๋งŒ. ํƒ์ƒ‰์šฉ best(objective)์™€ ๋‹ค๋ฅผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. +- ์žฅ์ด ์ข์•„์ง€๊ฑฐ๋‚˜ ๋ณ€๋™์„ฑ์ด ์ปค์ง€๋ฉด: ์†์ ˆยทํŠธ๋ ˆ์ผยท์‹œ๊ฐ„์ฐฝ์ด ๋จผ์ € ๊นจ์ง‘๋‹ˆ๋‹ค. ์Šน๋ฅ  ์ž๋ž‘๋ณด๋‹ค **์†์ ˆ์ด ์‚ด์•„ ์žˆ๋Š”์ง€**๋ฅผ ๋ณด์„ธ์š”. +- ํ˜„์žฌ ์‚ฌํ›„ํ•ฉ๊ฒฉ 0๊ฑด โ†’ ํŒŒ๋ผ๋ฏธํ„ฐ ์œ ์ง€(ํ˜„ํ–‰ DB) + ์œ ๋‹ˆ๋ฒ„์Šค/๋ฐ์ดํ„ฐ ์ ๊ฒ€์ด ์šฐ์„ ์ž…๋‹ˆ๋‹ค. + +_์ƒ์„ฑ: 2026-09-05 01:13:25 (rule)_ + +## AI ์ฝ”๋ฉ˜ํŠธ (์ด์ „ ์žฅ / ์•ž์œผ๋กœ ์žฅ) [gemini] + +## ์ด์ „ ์žฅ์—์„œ๋Š” +์ด์ „ ์žฅ ์‹ค๋งค๋Š” ์†์‹ค์ด์—ˆ๊ณ (์Šน๋ฅ  31%), **1์ผ ๋ฐฑํ…Œ ๊ฒฐ๊ณผ๋Š” ์œ ํšจํ•œ ์ „๋žต์„ ์ฐพ์ง€ ๋ชปํ–ˆ์Šต๋‹ˆ๋‹ค.** ์ด๋Š” **๊ทน๋‹จ์  ๋‹จ๊ธฐ ๋ฐ์ดํ„ฐ๋กœ ์ธํ•œ ๊ณผ์ ํ•ฉ ๋ฐ ํ‘œ๋ณธ ๋ถ€์กฑ** ์œ„ํ—˜์„ ๋ช…ํ™•ํžˆ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค. ๋ฐฑํ…Œ ํ†ต๊ณผ ์กฐํ•ฉ์ด 0๊ฑด์ด๋ฏ€๋กœ, ํŒŒ๋ผ๋ฏธํ„ฐ ์ ๊ฒ€์ด ํ•„์ˆ˜์ ์ž…๋‹ˆ๋‹ค. + +## ์•ž์œผ๋กœ ์žฅ์—์„œ๋Š” +**1์ผ ๋ฐฑํ…Œ ๊ฒฐ๊ณผ๋Š” ์ ˆ๋Œ€๋กœ ์ฆ‰์‹œ ์‹ค๋งค ์ ์šฉํ•ด์„  ์•ˆ ๋ฉ๋‹ˆ๋‹ค.** **๊ณผ์ ํ•ฉ ์œ„ํ—˜ 73% ํŒ์ •**์—์„œ ๋ณด๋“ฏ, **๋‹จ์ผ ์žฅ ๋ฐ์ดํ„ฐ๋Š” ํ‘œ๋ณธ ๋ถ€์กฑ๊ณผ ์šฐ์—ฐํ•œ ๊ฒฐ๊ณผ์ผ ๊ฐ€๋Šฅ์„ฑ์ด ๋งค์šฐ ๋†’์Šต๋‹ˆ๋‹ค.** **์‚ฌํ›„ํ•ฉ๊ฒฉ(gated)๋œ ์œ ํšจ ์ „๋žต์ด ์—†์œผ๋ฏ€๋กœ, ํ˜„ํ–‰ DB๋ฅผ ์œ ์ง€ํ•˜๋ฉฐ ์œ ๋‹ˆ๋ฒ„์Šค/๋ฐ์ดํ„ฐ ์žฌ๊ฒ€์ฆ์ด ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค.** mode Top10 1์œ„๋Š” ์ต์ ˆ ๋Œ€ํ‘œ๊ฐ€ ์•„๋‹ˆ๋ฉฐ, ๋ฐฑํ…Œ์™€ ์‹ค๋งค ๊ฐ„์˜ ๊ดด๋ฆฌ(๊ณ ์ŠคํŠธํผ์ง€ ๋“ฑ)๊ฐ€ ํด ์ˆ˜ ์žˆ์Œ์„ ๋ช…์‹ฌํ•˜์„ธ์š”. ํŠน์ • ์ข…๋ชฉ ๋งค์ˆ˜ ์ถ”์ฒœ์ด๋‚˜ ํ™•์ • ์ˆ˜์ต์€ ๋ณด์žฅ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. diff --git a/kis_trader/backtest/results/optuna_breakout_tpe_20260905_011459.briefing.md b/kis_trader/backtest/results/optuna_breakout_tpe_20260905_011459.briefing.md new file mode 100644 index 0000000..6e98585 --- /dev/null +++ b/kis_trader/backtest/results/optuna_breakout_tpe_20260905_011459.briefing.md @@ -0,0 +1,49 @@ +# Optuna ๋ธŒ๋ฆฌํ•‘ โ€” ๋ŒํŒŒ (tpe) +๊ธฐ๊ฐ„: 2026-09-04 ~ 2026-09-04 (๊ฑฐ๋ž˜์ผโ‰ˆ1์ผ) ยท trials 200/200 +ํƒ์ƒ‰ ๊ฒŒ์ดํŠธ: WRโ‰ฅ0% PFโ‰ฅ0 ยท min_tradesโ‰ฅ2 | ํ›„๋ณด ๊ฒŒ์ดํŠธ: WRโ‰ฅ40% PFโ‰ฅ1 ยท min_tradesโ‰ฅ2 +- min_trades=2: **ํ•ฉ๊ฒฉ ์ธ์ • ์ตœ์†Œ ๊ฑฐ๋ž˜ ๊ฑด์ˆ˜**(ํ‘œ๋ณธ ๋ถ€์กฑยท์šฐ์—ฐ ์Šน๋ฅ  ๋ฐฉ์ง€). ์ด๋ณด๋‹ค ์ ์€ ์กฐํ•ฉ์€ ํ•™์Šต/ํ›„๋ณด ์ง‘๊ณ„์—์„œ ์ œ์™ธ๋ฉ๋‹ˆ๋‹ค. +ํ•™์Šต์šฉ ํ†ต๊ณผ 0๊ฑด ยท ์‚ฌํ›„ํ•ฉ๊ฒฉ(results_gated) 0๊ฑด + +## ๊ณผ์ ํ•ฉยท์ ์šฉ ๊ฐ€๋Šฅ๋„ (ํœด๋ฆฌ์Šคํ‹ฑ) +- **๊ณผ์ ํ•ฉ ์œ„ํ—˜ 73.0%** ยท **์ ์šฉ ๊ฐ€๋Šฅ๋„ 27.0%** ยท ํŒ์ •: **๋น„๊ถŒ์žฅ** โ€” ๊ณผ์ ํ•ฉยทํ‘œ๋ณธ๋ถ€์กฑ ์œ„ํ—˜ ๋†’์Œ โ€” ์‹ค๋งค DB ์ฆ‰์‹œ ์ ์šฉ ๋น„๊ถŒ์žฅ + - ํ‘œ๋ณธ ์žฅ์ผ: +40.0p โ€” ๊ฑฐ๋ž˜์ผโ‰ˆ1์ผ โ€” ๋‹จ์ผ ์žฅ ๊ณผ์ ํ•ฉ ์œ„ํ—˜ ์ตœ๋Œ€ + - ๊ฑฐ๋ž˜ ํ‘œ๋ณธ: +25.0p โ€” ํ†ต๊ณผ ํ›„๋ณด ์—†์Œ โ€” ์ ์šฉ ๋ถˆ๊ฐ€ + - ์Šน๋ฅ ยทPF ์ด์ƒ์น˜: +0.0p โ€” ์ด์ƒ์น˜ ์—†์Œ + - ๊ฒŒ์ดํŠธ ์ปค๋ฒ„: +8.0p โ€” ํ•™์Šตยทgated ๋ชจ๋‘ ๋น„์–ด ์žˆ์Œ + - PnL ๊ณ ์›: +0.0p โ€” ๊ณ ์› ํŒ์ • ์Šคํ‚ต +- _์ฐธ๊ณ : ๊ณผ์ ํ•ฉ%๋Š” ๊ต์ฐจ๊ฒ€์ฆ ์ ์ˆ˜๊ฐ€ ์•„๋‹ˆ๋ผ ํ‘œ๋ณธยท์ด์ƒ์น˜ยท๊ณ ์› ํœด๋ฆฌ์Šคํ‹ฑ์ž…๋‹ˆ๋‹ค. ์ ์šฉ ๊ฐ€๋Šฅ๋„%=100โˆ’๊ณผ์ ํ•ฉ์œ„ํ—˜%. DB ์ ์šฉ ๋ฒ„ํŠผ ํ™œ์„ฑ ์กฐ๊ฑด(gated PnL>0)๊ณผ๋Š” ๋ณ„๊ฐœ์ž…๋‹ˆ๋‹ค._ + +## ์ตœ์ข… ์„ ํƒ ํ›„๋ณด (๊ทœ์น™ ยท DB ์ ์šฉ ์ „ ํ™•์ธ) +- ์•„๋ž˜๋Š” **์—ญํ• ์ด ๋‹ค๋ฅธ** 4์ข… ํ›„๋ณด์ž…๋‹ˆ๋‹ค. mode Top10 1์œ„ โ‰  ์ต์ ˆ ๋Œ€ํ‘œ ยท **DB 1์ˆœ์œ„๋Š” ์‚ฌํ›„ํ•ฉ๊ฒฉ(gated)** ์ž…๋‹ˆ๋‹ค. +- mode pool: `positive` ยท scoring: `band_proximity_p25_p75` + +### ํ›„๋ณด 4์ข… +- **โ‘  ์‚ฌํ›„ํ•ฉ๊ฒฉ 1์œ„ (apply: gated)**: ์—†์Œ +- **โ‘ก ์•ˆ์ • 1์œ„ (apply: stable)**: ์—†์Œ +- **โ‘ข mode_combo (apply: mode)**: ์—†์Œ (๋ฏธ์‚ฐ์ถœยท๊ตฌ JSON) +- **โ‘ฃ mode Top10 1์œ„ (apply: consensus ยท ๋ฐด๋“œ ์ „ํ˜• trial)**: ์—†์Œ +- mode Top10 meta: pool 0๊ฑด ยท ์ถ• 0๊ฐœ + +### ์ถ”์ฒœ (์ž๋™ ยท confirm ํ•„์ˆ˜) +1. **์‚ฌํ›„ํ•ฉ๊ฒฉ 0๊ฑด โ†’ DB ์ ์šฉ ๋น„๊ถŒ์žฅ.** ํ˜„ํ–‰ DB ์œ ์ง€ + ์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑยท๊ธฐ๊ฐ„ ์žฌ๊ฒ€์ฆ. +- โš  ์•ˆ์ • ๊ฒŒ์ดํŠธ 0๊ฑด โ†’ ์•ˆ์ • Top์€ **์ ์ˆ˜์ˆœ ํด๋ฐฑ** (์•ˆ์ • ๊ฒŒ์ดํŠธ 0๊ฑด โ†’ ํ•™์Šตํ’€ ์•ˆ์ •์ ์ˆ˜์ˆœ TopN (๋งˆ์ด๋„ˆ์Šค PnL ํฌํ•จ ยท ์ƒ๋Œ€๋น„๊ต)) + +## ์ด์ „ ์žฅ์—์„œ๋Š” +- ์‹ค๋งค ๋™๊ธฐ๊ฐ„ ์ฒญ์‚ฐ 13๊ฑด ยท ์Šน๋ฅ  31% ยท ํ•ฉ์‚ฐ PnL -34,618์› (๋ฐฑํ…Œ Optuna์™€ ์ˆซ์ž ๋‹ฌ๋ผ๋„ ์ •์ƒ โ€” ๊ณ ์ŠคํŠธยท์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑ ๊ฒฝ๋กœ ์ฐจ์ด). +- ์ด ๊ธฐ๊ฐ„ ๋ฐฑํ…Œ์—์„œ๋Š” **์œ ์˜๋ฏธํ•œ ํ†ต๊ณผ ์กฐํ•ฉ์ด ๊ฑฐ์˜ ์—†์—ˆ์Šต๋‹ˆ๋‹ค.** ์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑยท์†์ ˆยท์‹œ๊ฐ„์ฐฝ์„ ๋จผ์ € ์ ๊ฒ€ํ•˜์„ธ์š” (๋ŒํŒŒ 0๊ฑด์ด๋ฉด ํŠนํžˆ). + +## ์•ž์œผ๋กœ ์žฅ์—์„œ๋Š” +- **1~2์ผ Optuna best๋ฅผ ๋ฐ”๋กœ ์‹ค๋งค์— ๋„ฃ์ง€ ๋งˆ์„ธ์š”.** ๋‹ค์ผ(โ‰ฅ5๊ฑฐ๋ž˜์ผ) ์žฌ๊ฒ€์ฆยท์›น๋ฐฑํ…Œ 1ํšŒ ํ›„ ๊ฒ€ํ† . +- ์ ์šฉ ์‹œ์—๋Š” `results_gated` ํ›„๋ณด๋งŒ. ํƒ์ƒ‰์šฉ best(objective)์™€ ๋‹ค๋ฅผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. +- ์žฅ์ด ์ข์•„์ง€๊ฑฐ๋‚˜ ๋ณ€๋™์„ฑ์ด ์ปค์ง€๋ฉด: ์†์ ˆยทํŠธ๋ ˆ์ผยท์‹œ๊ฐ„์ฐฝ์ด ๋จผ์ € ๊นจ์ง‘๋‹ˆ๋‹ค. ์Šน๋ฅ  ์ž๋ž‘๋ณด๋‹ค **์†์ ˆ์ด ์‚ด์•„ ์žˆ๋Š”์ง€**๋ฅผ ๋ณด์„ธ์š”. +- ํ˜„์žฌ ์‚ฌํ›„ํ•ฉ๊ฒฉ 0๊ฑด โ†’ ํŒŒ๋ผ๋ฏธํ„ฐ ์œ ์ง€(ํ˜„ํ–‰ DB) + ์œ ๋‹ˆ๋ฒ„์Šค/๋ฐ์ดํ„ฐ ์ ๊ฒ€์ด ์šฐ์„ ์ž…๋‹ˆ๋‹ค. + +_์ƒ์„ฑ: 2026-09-05 01:15:00 (rule)_ + +## AI ์ฝ”๋ฉ˜ํŠธ (์ด์ „ ์žฅ / ์•ž์œผ๋กœ ์žฅ) [gemini] + +## ์ด์ „ ์žฅ์—์„œ๋Š” +์ง€๋‚œ ํ•˜๋ฃจ ์‹ค๋งค๋Š” 13๊ฑด ์ค‘ 31% ์Šน๋ฅ ๋กœ -34,618์› ์†์‹ค์„ ๊ธฐ๋กํ–ˆ์Šต๋‹ˆ๋‹ค. ๋ฐฑํ…Œ์ŠคํŠธ์—์„œ๋Š” ์œ ์˜๋ฏธํ•œ ์กฐํ•ฉ์ด ์ „๋ฌดํ•˜๋ฉฐ, 1์ผ ๋‹จ๊ธฐ ํ…Œ์ŠคํŠธ๋Š” ๊ณผ์ ํ•ฉ ์œ„ํ—˜ 73%๋กœ '๋น„๊ถŒ์žฅ' ํŒ์ •์ž…๋‹ˆ๋‹ค. ์‹ค๋งค์™€ ๋ฐฑํ…Œ PnL ๊ดด๋ฆฌ๋Š” ๊ณ ์ŠคํŠธ์Šคํ”„๋ ˆ๋“œ ๋“ฑ์œผ๋กœ ํ•ญ์ƒ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. + +## ์•ž์œผ๋กœ ์žฅ์—์„œ๋Š” +๋ณธ 1์ผ ํ…Œ์ŠคํŠธ๋Š” ๊ณผ์ ํ•ฉ 73%, ํ‘œ๋ณธ ๋ถ€์กฑ์œผ๋กœ ์‹ค๋งค ์ ์šฉ์ด '๋น„๊ถŒ์žฅ'๋ฉ๋‹ˆ๋‹ค. DB 1์ˆœ์œ„๋Š” ์‚ฌํ›„ํ•ฉ๊ฒฉ(gated)์ด๋ฉฐ, mode Top10 1์œ„๊ฐ€ ์ต์ ˆ ๋Œ€ํ‘œ๋Š” ์•„๋‹™๋‹ˆ๋‹ค. ์‚ฌํ›„ํ•ฉ๊ฒฉ ์กฐํ•ฉ 0๊ฑด์ด๋‹ˆ, ํ˜„ํ–‰ DB ์œ ์ง€ ๋ฐ ์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑยท๊ธฐ๊ฐ„ ์žฌ๊ฒ€์ฆ์ด ์šฐ์„ ์ž…๋‹ˆ๋‹ค. ๋ฐฑํ…Œ์™€ ์‹ค๋งค ๊ดด๋ฆฌ(๊ณ ์ŠคํŠธํผ์ง€ ๋“ฑ)๊ฐ€ ํฌ๋ฏ€๋กœ ์„ฃ๋ถ€๋ฅธ ์ ์šฉ์ด๋‚˜ ํ™•์ • ์ˆ˜์ต ๊ธฐ๋Œ€๋Š” ์ ˆ๋Œ€ ๊ธˆ๋ฌผ์ž…๋‹ˆ๋‹ค. diff --git a/kis_trader/backtest/results/optuna_breakout_tpe_20260905_012114.briefing.md b/kis_trader/backtest/results/optuna_breakout_tpe_20260905_012114.briefing.md new file mode 100644 index 0000000..0d44fe8 --- /dev/null +++ b/kis_trader/backtest/results/optuna_breakout_tpe_20260905_012114.briefing.md @@ -0,0 +1,51 @@ +# Optuna ๋ธŒ๋ฆฌํ•‘ โ€” ๋ŒํŒŒ (tpe) +๊ธฐ๊ฐ„: 2026-09-04 ~ 2026-09-04 (๊ฑฐ๋ž˜์ผโ‰ˆ1์ผ) ยท trials 200/200 +ํƒ์ƒ‰ ๊ฒŒ์ดํŠธ: WRโ‰ฅ0% PFโ‰ฅ0 ยท min_tradesโ‰ฅ2 | ํ›„๋ณด ๊ฒŒ์ดํŠธ: WRโ‰ฅ40% PFโ‰ฅ1 ยท min_tradesโ‰ฅ2 +- min_trades=2: **ํ•ฉ๊ฒฉ ์ธ์ • ์ตœ์†Œ ๊ฑฐ๋ž˜ ๊ฑด์ˆ˜**(ํ‘œ๋ณธ ๋ถ€์กฑยท์šฐ์—ฐ ์Šน๋ฅ  ๋ฐฉ์ง€). ์ด๋ณด๋‹ค ์ ์€ ์กฐํ•ฉ์€ ํ•™์Šต/ํ›„๋ณด ์ง‘๊ณ„์—์„œ ์ œ์™ธ๋ฉ๋‹ˆ๋‹ค. +ํ•™์Šต์šฉ ํ†ต๊ณผ 0๊ฑด ยท ์‚ฌํ›„ํ•ฉ๊ฒฉ(results_gated) 0๊ฑด + +## ๊ณผ์ ํ•ฉยท์ ์šฉ ๊ฐ€๋Šฅ๋„ (ํœด๋ฆฌ์Šคํ‹ฑ) +- **๊ณผ์ ํ•ฉ ์œ„ํ—˜ 73.0%** ยท **์ ์šฉ ๊ฐ€๋Šฅ๋„ 27.0%** ยท ํŒ์ •: **๋น„๊ถŒ์žฅ** โ€” ๊ณผ์ ํ•ฉยทํ‘œ๋ณธ๋ถ€์กฑ ์œ„ํ—˜ ๋†’์Œ โ€” ์‹ค๋งค DB ์ฆ‰์‹œ ์ ์šฉ ๋น„๊ถŒ์žฅ + - ํ‘œ๋ณธ ์žฅ์ผ: +40.0p โ€” ๊ฑฐ๋ž˜์ผโ‰ˆ1์ผ โ€” ๋‹จ์ผ ์žฅ ๊ณผ์ ํ•ฉ ์œ„ํ—˜ ์ตœ๋Œ€ + - ๊ฑฐ๋ž˜ ํ‘œ๋ณธ: +25.0p โ€” ํ†ต๊ณผ ํ›„๋ณด ์—†์Œ โ€” ์ ์šฉ ๋ถˆ๊ฐ€ + - ์Šน๋ฅ ยทPF ์ด์ƒ์น˜: +0.0p โ€” ์ด์ƒ์น˜ ์—†์Œ + - ๊ฒŒ์ดํŠธ ์ปค๋ฒ„: +8.0p โ€” ํ•™์Šตยทgated ๋ชจ๋‘ ๋น„์–ด ์žˆ์Œ + - PnL ๊ณ ์›: +0.0p โ€” ๊ณ ์› ํŒ์ • ์Šคํ‚ต +- _์ฐธ๊ณ : ๊ณผ์ ํ•ฉ%๋Š” ๊ต์ฐจ๊ฒ€์ฆ ์ ์ˆ˜๊ฐ€ ์•„๋‹ˆ๋ผ ํ‘œ๋ณธยท์ด์ƒ์น˜ยท๊ณ ์› ํœด๋ฆฌ์Šคํ‹ฑ์ž…๋‹ˆ๋‹ค. ์ ์šฉ ๊ฐ€๋Šฅ๋„%=100โˆ’๊ณผ์ ํ•ฉ์œ„ํ—˜%. DB ์ ์šฉ ๋ฒ„ํŠผ ํ™œ์„ฑ ์กฐ๊ฑด(gated PnL>0)๊ณผ๋Š” ๋ณ„๊ฐœ์ž…๋‹ˆ๋‹ค._ + +## ์ตœ์ข… ์„ ํƒ ํ›„๋ณด (๊ทœ์น™ ยท DB ์ ์šฉ ์ „ ํ™•์ธ) +- ์•„๋ž˜๋Š” **์—ญํ• ์ด ๋‹ค๋ฅธ** 4์ข… ํ›„๋ณด์ž…๋‹ˆ๋‹ค. mode Top10 1์œ„ โ‰  ์ต์ ˆ ๋Œ€ํ‘œ ยท **DB 1์ˆœ์œ„๋Š” ์‚ฌํ›„ํ•ฉ๊ฒฉ(gated)** ์ž…๋‹ˆ๋‹ค. +- mode pool: `positive` ยท scoring: `band_proximity_p25_p75` + +### ํ›„๋ณด 4์ข… +- **โ‘  ์‚ฌํ›„ํ•ฉ๊ฒฉ 1์œ„ (apply: gated)**: ์—†์Œ +- **โ‘ก ์•ˆ์ • 1์œ„ (apply: stable)**: ์—†์Œ +- **โ‘ข mode_combo (apply: mode)**: ์—†์Œ (๋ฏธ์‚ฐ์ถœยท๊ตฌ JSON) +- **โ‘ฃ mode Top10 1์œ„ (apply: consensus ยท ๋ฐด๋“œ ์ „ํ˜• trial)**: ์—†์Œ +- mode Top10 meta: pool 0๊ฑด ยท ์ถ• 0๊ฐœ + +### ์ถ”์ฒœ (์ž๋™ ยท confirm ํ•„์ˆ˜) +1. **์‚ฌํ›„ํ•ฉ๊ฒฉ 0๊ฑด โ†’ DB ์ ์šฉ ๋น„๊ถŒ์žฅ.** ํ˜„ํ–‰ DB ์œ ์ง€ + ์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑยท๊ธฐ๊ฐ„ ์žฌ๊ฒ€์ฆ. +- โš  ์•ˆ์ • ๊ฒŒ์ดํŠธ 0๊ฑด โ†’ ์•ˆ์ • Top์€ **์ ์ˆ˜์ˆœ ํด๋ฐฑ** (์•ˆ์ • ๊ฒŒ์ดํŠธ 0๊ฑด โ†’ ํ•™์Šตํ’€ ์•ˆ์ •์ ์ˆ˜์ˆœ TopN (๋งˆ์ด๋„ˆ์Šค PnL ํฌํ•จ ยท ์ƒ๋Œ€๋น„๊ต)) + +## ์ด์ „ ์žฅ์—์„œ๋Š” +- ์‹ค๋งค ๋™๊ธฐ๊ฐ„ ์ฒญ์‚ฐ 13๊ฑด ยท ์Šน๋ฅ  31% ยท ํ•ฉ์‚ฐ PnL -34,618์› (๋ฐฑํ…Œ Optuna์™€ ์ˆซ์ž ๋‹ฌ๋ผ๋„ ์ •์ƒ โ€” ๊ณ ์ŠคํŠธยท์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑ ๊ฒฝ๋กœ ์ฐจ์ด). +- ์ด ๊ธฐ๊ฐ„ ๋ฐฑํ…Œ์—์„œ๋Š” **์œ ์˜๋ฏธํ•œ ํ†ต๊ณผ ์กฐํ•ฉ์ด ๊ฑฐ์˜ ์—†์—ˆ์Šต๋‹ˆ๋‹ค.** ์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑยท์†์ ˆยท์‹œ๊ฐ„์ฐฝ์„ ๋จผ์ € ์ ๊ฒ€ํ•˜์„ธ์š” (๋ŒํŒŒ 0๊ฑด์ด๋ฉด ํŠนํžˆ). + +## ์•ž์œผ๋กœ ์žฅ์—์„œ๋Š” +- **1~2์ผ Optuna best๋ฅผ ๋ฐ”๋กœ ์‹ค๋งค์— ๋„ฃ์ง€ ๋งˆ์„ธ์š”.** ๋‹ค์ผ(โ‰ฅ5๊ฑฐ๋ž˜์ผ) ์žฌ๊ฒ€์ฆยท์›น๋ฐฑํ…Œ 1ํšŒ ํ›„ ๊ฒ€ํ† . +- ์ ์šฉ ์‹œ์—๋Š” `results_gated` ํ›„๋ณด๋งŒ. ํƒ์ƒ‰์šฉ best(objective)์™€ ๋‹ค๋ฅผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. +- ์žฅ์ด ์ข์•„์ง€๊ฑฐ๋‚˜ ๋ณ€๋™์„ฑ์ด ์ปค์ง€๋ฉด: ์†์ ˆยทํŠธ๋ ˆ์ผยท์‹œ๊ฐ„์ฐฝ์ด ๋จผ์ € ๊นจ์ง‘๋‹ˆ๋‹ค. ์Šน๋ฅ  ์ž๋ž‘๋ณด๋‹ค **์†์ ˆ์ด ์‚ด์•„ ์žˆ๋Š”์ง€**๋ฅผ ๋ณด์„ธ์š”. +- ํ˜„์žฌ ์‚ฌํ›„ํ•ฉ๊ฒฉ 0๊ฑด โ†’ ํŒŒ๋ผ๋ฏธํ„ฐ ์œ ์ง€(ํ˜„ํ–‰ DB) + ์œ ๋‹ˆ๋ฒ„์Šค/๋ฐ์ดํ„ฐ ์ ๊ฒ€์ด ์šฐ์„ ์ž…๋‹ˆ๋‹ค. + +_์ƒ์„ฑ: 2026-09-05 01:21:14 (rule)_ + +## AI ์ฝ”๋ฉ˜ํŠธ (์ด์ „ ์žฅ / ์•ž์œผ๋กœ ์žฅ) [gemini] + +## ์ด์ „ ์žฅ์—์„œ๋Š” + +๋‹จ ํ•˜๋ฃจ(1์ผ)์˜ ์งง์€ ๋ฐฑํ…Œ์ŠคํŠธ ๊ธฐ๊ฐ„์œผ๋กœ ์ธํ•ด ๊ณผ์ ํ•ฉ ์œ„ํ—˜์ด 73%์— ๋‹ฌํ•˜๋ฉฐ, ์‹ค์ œ ์ ์šฉ ๊ฐ€๋Šฅ์„ฑ์€ 27%์— ๋ถˆ๊ณผํ•ฉ๋‹ˆ๋‹ค. ์ตœ์†Œ ๊ฑฐ๋ž˜ ๊ฑด์ˆ˜(min_trades=2) ๊ธฐ์ค€์„ ์ถฉ์กฑํ•˜๋Š” ์œ ์˜๋ฏธํ•œ ์กฐํ•ฉ์ด ์ „ํ˜€ ๋„์ถœ๋˜์ง€ ์•Š์•„ ํ‘œ๋ณธ ๋ถ€์กฑ์ด ์‹ฌ๊ฐํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” ์‹ค๋งค ๋™๊ธฐ๊ฐ„ ์ฒญ์‚ฐ ๋ฐ์ดํ„ฐ์™€๋„ ํฐ ๊ดด๋ฆฌ๊ฐ€ ์žˆ์„ ์ˆ˜ ์žˆ์Œ์„ ์‹œ์‚ฌํ•ฉ๋‹ˆ๋‹ค. + +## ์•ž์œผ๋กœ ์žฅ์—์„œ๋Š” + +๊ธˆ๋ฒˆ 1์ผ ๋ฐฑํ…Œ์ŠคํŠธ ๊ฒฐ๊ณผ๋Š” ์ฆ‰์‹œ ์‹ค๋งค ์ ์šฉ์ด ์ ˆ๋Œ€ ๋ถˆ๊ฐ€ํ•ฉ๋‹ˆ๋‹ค. ๊ณผ์ ํ•ฉ ๋ฐ ํ‘œ๋ณธ ๋ถ€์กฑ ์œ„ํ—˜์ด ๋งค์šฐ ๋†’์•„ ์‹ค๋งค ํ™˜๊ฒฝ์—์„œ๋Š” ๋ฐฑํ…Œ์ŠคํŠธ ๊ฒฐ๊ณผ์™€ ์‹ฌ๊ฐํ•œ ๊ดด๋ฆฌ(๊ณ ์ŠคํŠธํผ์ง€ ๋“ฑ)๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. `mode Top10 1์œ„`๋ฅผ ์ต์ ˆ ๋Œ€ํ‘œ๋กœ ๋‹จ์ •ํ•ด์„  ์•ˆ ๋˜๋ฉฐ, ์ตœ์ข… ์ ์šฉ์€ `์‚ฌํ›„ํ•ฉ๊ฒฉ(gated)` ํ›„๋ณด๋งŒ ๊ฐ€๋Šฅํ•˜๋‚˜, ํ˜„์žฌ 0๊ฑด์ด๋ฏ€๋กœ ํŒŒ๋ผ๋ฏธํ„ฐ ์žฌ๊ฒ€ํ† ์™€ ๋‹ค์ผ(โ‰ฅ5๊ฑฐ๋ž˜์ผ) ๊ต์ฐจ ๊ฒ€์ฆ์ด ํ•„์ˆ˜์ ์ž…๋‹ˆ๋‹ค. ์œ ๋‹ˆ๋ฒ„์Šค, ํ‹ฑ, ์†์ ˆ๋งค ์„ค์ • ๋“ฑ์„ ๋ฉด๋ฐ€ํžˆ ์žฌ์ ๊ฒ€ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. diff --git a/kis_trader/backtest/results/optuna_breakout_tpe_20260905_012224.briefing.md b/kis_trader/backtest/results/optuna_breakout_tpe_20260905_012224.briefing.md new file mode 100644 index 0000000..3cb146c --- /dev/null +++ b/kis_trader/backtest/results/optuna_breakout_tpe_20260905_012224.briefing.md @@ -0,0 +1,49 @@ +# Optuna ๋ธŒ๋ฆฌํ•‘ โ€” ๋ŒํŒŒ (tpe) +๊ธฐ๊ฐ„: 2026-09-04 ~ 2026-09-04 (๊ฑฐ๋ž˜์ผโ‰ˆ1์ผ) ยท trials 200/200 +ํƒ์ƒ‰ ๊ฒŒ์ดํŠธ: WRโ‰ฅ0% PFโ‰ฅ0 ยท min_tradesโ‰ฅ2 | ํ›„๋ณด ๊ฒŒ์ดํŠธ: WRโ‰ฅ40% PFโ‰ฅ1 ยท min_tradesโ‰ฅ2 +- min_trades=2: **ํ•ฉ๊ฒฉ ์ธ์ • ์ตœ์†Œ ๊ฑฐ๋ž˜ ๊ฑด์ˆ˜**(ํ‘œ๋ณธ ๋ถ€์กฑยท์šฐ์—ฐ ์Šน๋ฅ  ๋ฐฉ์ง€). ์ด๋ณด๋‹ค ์ ์€ ์กฐํ•ฉ์€ ํ•™์Šต/ํ›„๋ณด ์ง‘๊ณ„์—์„œ ์ œ์™ธ๋ฉ๋‹ˆ๋‹ค. +ํ•™์Šต์šฉ ํ†ต๊ณผ 0๊ฑด ยท ์‚ฌํ›„ํ•ฉ๊ฒฉ(results_gated) 0๊ฑด + +## ๊ณผ์ ํ•ฉยท์ ์šฉ ๊ฐ€๋Šฅ๋„ (ํœด๋ฆฌ์Šคํ‹ฑ) +- **๊ณผ์ ํ•ฉ ์œ„ํ—˜ 73.0%** ยท **์ ์šฉ ๊ฐ€๋Šฅ๋„ 27.0%** ยท ํŒ์ •: **๋น„๊ถŒ์žฅ** โ€” ๊ณผ์ ํ•ฉยทํ‘œ๋ณธ๋ถ€์กฑ ์œ„ํ—˜ ๋†’์Œ โ€” ์‹ค๋งค DB ์ฆ‰์‹œ ์ ์šฉ ๋น„๊ถŒ์žฅ + - ํ‘œ๋ณธ ์žฅ์ผ: +40.0p โ€” ๊ฑฐ๋ž˜์ผโ‰ˆ1์ผ โ€” ๋‹จ์ผ ์žฅ ๊ณผ์ ํ•ฉ ์œ„ํ—˜ ์ตœ๋Œ€ + - ๊ฑฐ๋ž˜ ํ‘œ๋ณธ: +25.0p โ€” ํ†ต๊ณผ ํ›„๋ณด ์—†์Œ โ€” ์ ์šฉ ๋ถˆ๊ฐ€ + - ์Šน๋ฅ ยทPF ์ด์ƒ์น˜: +0.0p โ€” ์ด์ƒ์น˜ ์—†์Œ + - ๊ฒŒ์ดํŠธ ์ปค๋ฒ„: +8.0p โ€” ํ•™์Šตยทgated ๋ชจ๋‘ ๋น„์–ด ์žˆ์Œ + - PnL ๊ณ ์›: +0.0p โ€” ๊ณ ์› ํŒ์ • ์Šคํ‚ต +- _์ฐธ๊ณ : ๊ณผ์ ํ•ฉ%๋Š” ๊ต์ฐจ๊ฒ€์ฆ ์ ์ˆ˜๊ฐ€ ์•„๋‹ˆ๋ผ ํ‘œ๋ณธยท์ด์ƒ์น˜ยท๊ณ ์› ํœด๋ฆฌ์Šคํ‹ฑ์ž…๋‹ˆ๋‹ค. ์ ์šฉ ๊ฐ€๋Šฅ๋„%=100โˆ’๊ณผ์ ํ•ฉ์œ„ํ—˜%. DB ์ ์šฉ ๋ฒ„ํŠผ ํ™œ์„ฑ ์กฐ๊ฑด(gated PnL>0)๊ณผ๋Š” ๋ณ„๊ฐœ์ž…๋‹ˆ๋‹ค._ + +## ์ตœ์ข… ์„ ํƒ ํ›„๋ณด (๊ทœ์น™ ยท DB ์ ์šฉ ์ „ ํ™•์ธ) +- ์•„๋ž˜๋Š” **์—ญํ• ์ด ๋‹ค๋ฅธ** 4์ข… ํ›„๋ณด์ž…๋‹ˆ๋‹ค. mode Top10 1์œ„ โ‰  ์ต์ ˆ ๋Œ€ํ‘œ ยท **DB 1์ˆœ์œ„๋Š” ์‚ฌํ›„ํ•ฉ๊ฒฉ(gated)** ์ž…๋‹ˆ๋‹ค. +- mode pool: `positive` ยท scoring: `band_proximity_p25_p75` + +### ํ›„๋ณด 4์ข… +- **โ‘  ์‚ฌํ›„ํ•ฉ๊ฒฉ 1์œ„ (apply: gated)**: ์—†์Œ +- **โ‘ก ์•ˆ์ • 1์œ„ (apply: stable)**: ์—†์Œ +- **โ‘ข mode_combo (apply: mode)**: ์—†์Œ (๋ฏธ์‚ฐ์ถœยท๊ตฌ JSON) +- **โ‘ฃ mode Top10 1์œ„ (apply: consensus ยท ๋ฐด๋“œ ์ „ํ˜• trial)**: ์—†์Œ +- mode Top10 meta: pool 0๊ฑด ยท ์ถ• 0๊ฐœ + +### ์ถ”์ฒœ (์ž๋™ ยท confirm ํ•„์ˆ˜) +1. **์‚ฌํ›„ํ•ฉ๊ฒฉ 0๊ฑด โ†’ DB ์ ์šฉ ๋น„๊ถŒ์žฅ.** ํ˜„ํ–‰ DB ์œ ์ง€ + ์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑยท๊ธฐ๊ฐ„ ์žฌ๊ฒ€์ฆ. +- โš  ์•ˆ์ • ๊ฒŒ์ดํŠธ 0๊ฑด โ†’ ์•ˆ์ • Top์€ **์ ์ˆ˜์ˆœ ํด๋ฐฑ** (์•ˆ์ • ๊ฒŒ์ดํŠธ 0๊ฑด โ†’ ํ•™์Šตํ’€ ์•ˆ์ •์ ์ˆ˜์ˆœ TopN (๋งˆ์ด๋„ˆ์Šค PnL ํฌํ•จ ยท ์ƒ๋Œ€๋น„๊ต)) + +## ์ด์ „ ์žฅ์—์„œ๋Š” +- ์‹ค๋งค ๋™๊ธฐ๊ฐ„ ์ฒญ์‚ฐ 13๊ฑด ยท ์Šน๋ฅ  31% ยท ํ•ฉ์‚ฐ PnL -34,618์› (๋ฐฑํ…Œ Optuna์™€ ์ˆซ์ž ๋‹ฌ๋ผ๋„ ์ •์ƒ โ€” ๊ณ ์ŠคํŠธยท์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑ ๊ฒฝ๋กœ ์ฐจ์ด). +- ์ด ๊ธฐ๊ฐ„ ๋ฐฑํ…Œ์—์„œ๋Š” **์œ ์˜๋ฏธํ•œ ํ†ต๊ณผ ์กฐํ•ฉ์ด ๊ฑฐ์˜ ์—†์—ˆ์Šต๋‹ˆ๋‹ค.** ์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑยท์†์ ˆยท์‹œ๊ฐ„์ฐฝ์„ ๋จผ์ € ์ ๊ฒ€ํ•˜์„ธ์š” (๋ŒํŒŒ 0๊ฑด์ด๋ฉด ํŠนํžˆ). + +## ์•ž์œผ๋กœ ์žฅ์—์„œ๋Š” +- **1~2์ผ Optuna best๋ฅผ ๋ฐ”๋กœ ์‹ค๋งค์— ๋„ฃ์ง€ ๋งˆ์„ธ์š”.** ๋‹ค์ผ(โ‰ฅ5๊ฑฐ๋ž˜์ผ) ์žฌ๊ฒ€์ฆยท์›น๋ฐฑํ…Œ 1ํšŒ ํ›„ ๊ฒ€ํ† . +- ์ ์šฉ ์‹œ์—๋Š” `results_gated` ํ›„๋ณด๋งŒ. ํƒ์ƒ‰์šฉ best(objective)์™€ ๋‹ค๋ฅผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. +- ์žฅ์ด ์ข์•„์ง€๊ฑฐ๋‚˜ ๋ณ€๋™์„ฑ์ด ์ปค์ง€๋ฉด: ์†์ ˆยทํŠธ๋ ˆ์ผยท์‹œ๊ฐ„์ฐฝ์ด ๋จผ์ € ๊นจ์ง‘๋‹ˆ๋‹ค. ์Šน๋ฅ  ์ž๋ž‘๋ณด๋‹ค **์†์ ˆ์ด ์‚ด์•„ ์žˆ๋Š”์ง€**๋ฅผ ๋ณด์„ธ์š”. +- ํ˜„์žฌ ์‚ฌํ›„ํ•ฉ๊ฒฉ 0๊ฑด โ†’ ํŒŒ๋ผ๋ฏธํ„ฐ ์œ ์ง€(ํ˜„ํ–‰ DB) + ์œ ๋‹ˆ๋ฒ„์Šค/๋ฐ์ดํ„ฐ ์ ๊ฒ€์ด ์šฐ์„ ์ž…๋‹ˆ๋‹ค. + +_์ƒ์„ฑ: 2026-09-05 01:22:24 (rule)_ + +## AI ์ฝ”๋ฉ˜ํŠธ (์ด์ „ ์žฅ / ์•ž์œผ๋กœ ์žฅ) [gemini] + +**์ด์ „ ์žฅ์—์„œ๋Š”** +์ง€๋‚œ ํ•˜๋ฃจ(2026-09-04) ๋™์•ˆ์˜ Optuna TPE ํƒ์ƒ‰ ๊ฒฐ๊ณผ, ์„ค์ •๋œ ๊ธฐ์ค€(WR 40%, PF 1, ์ตœ์†Œ ๊ฑฐ๋ž˜ 2๊ฑด)์„ ๋งŒ์กฑํ•˜๋Š” ์œ ํšจํ•œ ์ „๋žต ์กฐํ•ฉ์ด **์ „ํ˜€ ๋ฐœ๊ฒฌ๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.** ์‹ค๋งค์—์„œ๋Š” ๋™ ๊ธฐ๊ฐ„ 13๊ฑด ์ฒญ์‚ฐ, ์Šน๋ฅ  31%, -34,618์› PnL์ด ๋ฐœ์ƒํ–ˆ๋Š”๋ฐ, ๋ฐฑํ…Œ์ŠคํŠธ ๊ฒฐ๊ณผ์™€ ์‹ค๋งค ํ™˜๊ฒฝ(์œ ๋‹ˆ๋ฒ„์Šค, ํ‹ฑ, ๊ณ ์ŠคํŠธ ์Šคํ”„๋ ˆ๋“œ ๋“ฑ)์˜ ์ฐจ์ด๋กœ ๊ดด๋ฆฌ๊ฐ€ ์žˆ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. + +**์•ž์œผ๋กœ ์žฅ์—์„œ๋Š”** +ํ˜„์žฌ ๊ณผ์ ํ•ฉ ์œ„ํ—˜ 73.0%, ๋‹จ์ผ ๊ฑฐ๋ž˜์ผ ํƒ์ƒ‰์œผ๋กœ ์ธํ•œ ํ‘œ๋ณธ ๋ถ€์กฑ ์œ„ํ—˜์ด ๋งค์šฐ ๋†’์Šต๋‹ˆ๋‹ค. ์ด ๊ฒฐ๊ณผ๋ฅผ ์‹ค๋งค์— **์ฆ‰์‹œ ์ ์šฉํ•˜๋Š” ๊ฒƒ์€ ์ ˆ๋Œ€ ๋น„๊ถŒ์žฅ**ํ•ฉ๋‹ˆ๋‹ค. ์‚ฌํ›„ํ•ฉ๊ฒฉ(gated) ํ›„๋ณด 0๊ฑด์ด๋ฏ€๋กœ, ๊ธฐ์กด DB๋ฅผ ์œ ์ง€ํ•˜๊ณ  ์ƒˆ๋กœ์šด ์ „๋žต ์ถ”๊ฐ€๋Š” ๋ณด๋ฅ˜ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๋ฐฑํ…Œ์ŠคํŠธ ๊ฒฐ๊ณผ๋Š” ์‹ค๋งค ํ™˜๊ฒฝ(๊ณ ์ŠคํŠธ ์Šคํ”„๋ ˆ๋“œ ๋“ฑ)๊ณผ ํฐ ๊ดด๋ฆฌ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์œผ๋‹ˆ ์ฃผ์˜ํ•˜์‹ญ์‹œ์˜ค. ์ตœ์†Œ 5๊ฑฐ๋ž˜์ผ ์ด์ƒ ์žฌ๊ฒ€์ฆ ํ›„ ์‹ ์ค‘ํžˆ ๊ฒ€ํ† ํ•˜๋ฉฐ, ์Šน๋ฅ ๋ณด๋‹ค๋Š” ์†์ ˆ ๊ธฐ๋Šฅ ํ™œ์„ฑํ™” ์—ฌ๋ถ€์™€ ์œ ๋‹ˆ๋ฒ„์Šค/๋ฐ์ดํ„ฐ ์ ๊ฒ€์ด ์šฐ์„ ์ž…๋‹ˆ๋‹ค. diff --git a/kis_trader/backtest/results/optuna_breakout_tpe_20260905_012403.briefing.md b/kis_trader/backtest/results/optuna_breakout_tpe_20260905_012403.briefing.md new file mode 100644 index 0000000..abddb7f --- /dev/null +++ b/kis_trader/backtest/results/optuna_breakout_tpe_20260905_012403.briefing.md @@ -0,0 +1,49 @@ +# Optuna ๋ธŒ๋ฆฌํ•‘ โ€” ๋ŒํŒŒ (tpe) +๊ธฐ๊ฐ„: 2026-09-04 ~ 2026-09-04 (๊ฑฐ๋ž˜์ผโ‰ˆ1์ผ) ยท trials 200/200 +ํƒ์ƒ‰ ๊ฒŒ์ดํŠธ: WRโ‰ฅ0% PFโ‰ฅ0 ยท min_tradesโ‰ฅ2 | ํ›„๋ณด ๊ฒŒ์ดํŠธ: WRโ‰ฅ40% PFโ‰ฅ1 ยท min_tradesโ‰ฅ2 +- min_trades=2: **ํ•ฉ๊ฒฉ ์ธ์ • ์ตœ์†Œ ๊ฑฐ๋ž˜ ๊ฑด์ˆ˜**(ํ‘œ๋ณธ ๋ถ€์กฑยท์šฐ์—ฐ ์Šน๋ฅ  ๋ฐฉ์ง€). ์ด๋ณด๋‹ค ์ ์€ ์กฐํ•ฉ์€ ํ•™์Šต/ํ›„๋ณด ์ง‘๊ณ„์—์„œ ์ œ์™ธ๋ฉ๋‹ˆ๋‹ค. +ํ•™์Šต์šฉ ํ†ต๊ณผ 0๊ฑด ยท ์‚ฌํ›„ํ•ฉ๊ฒฉ(results_gated) 0๊ฑด + +## ๊ณผ์ ํ•ฉยท์ ์šฉ ๊ฐ€๋Šฅ๋„ (ํœด๋ฆฌ์Šคํ‹ฑ) +- **๊ณผ์ ํ•ฉ ์œ„ํ—˜ 73.0%** ยท **์ ์šฉ ๊ฐ€๋Šฅ๋„ 27.0%** ยท ํŒ์ •: **๋น„๊ถŒ์žฅ** โ€” ๊ณผ์ ํ•ฉยทํ‘œ๋ณธ๋ถ€์กฑ ์œ„ํ—˜ ๋†’์Œ โ€” ์‹ค๋งค DB ์ฆ‰์‹œ ์ ์šฉ ๋น„๊ถŒ์žฅ + - ํ‘œ๋ณธ ์žฅ์ผ: +40.0p โ€” ๊ฑฐ๋ž˜์ผโ‰ˆ1์ผ โ€” ๋‹จ์ผ ์žฅ ๊ณผ์ ํ•ฉ ์œ„ํ—˜ ์ตœ๋Œ€ + - ๊ฑฐ๋ž˜ ํ‘œ๋ณธ: +25.0p โ€” ํ†ต๊ณผ ํ›„๋ณด ์—†์Œ โ€” ์ ์šฉ ๋ถˆ๊ฐ€ + - ์Šน๋ฅ ยทPF ์ด์ƒ์น˜: +0.0p โ€” ์ด์ƒ์น˜ ์—†์Œ + - ๊ฒŒ์ดํŠธ ์ปค๋ฒ„: +8.0p โ€” ํ•™์Šตยทgated ๋ชจ๋‘ ๋น„์–ด ์žˆ์Œ + - PnL ๊ณ ์›: +0.0p โ€” ๊ณ ์› ํŒ์ • ์Šคํ‚ต +- _์ฐธ๊ณ : ๊ณผ์ ํ•ฉ%๋Š” ๊ต์ฐจ๊ฒ€์ฆ ์ ์ˆ˜๊ฐ€ ์•„๋‹ˆ๋ผ ํ‘œ๋ณธยท์ด์ƒ์น˜ยท๊ณ ์› ํœด๋ฆฌ์Šคํ‹ฑ์ž…๋‹ˆ๋‹ค. ์ ์šฉ ๊ฐ€๋Šฅ๋„%=100โˆ’๊ณผ์ ํ•ฉ์œ„ํ—˜%. DB ์ ์šฉ ๋ฒ„ํŠผ ํ™œ์„ฑ ์กฐ๊ฑด(gated PnL>0)๊ณผ๋Š” ๋ณ„๊ฐœ์ž…๋‹ˆ๋‹ค._ + +## ์ตœ์ข… ์„ ํƒ ํ›„๋ณด (๊ทœ์น™ ยท DB ์ ์šฉ ์ „ ํ™•์ธ) +- ์•„๋ž˜๋Š” **์—ญํ• ์ด ๋‹ค๋ฅธ** 4์ข… ํ›„๋ณด์ž…๋‹ˆ๋‹ค. mode Top10 1์œ„ โ‰  ์ต์ ˆ ๋Œ€ํ‘œ ยท **DB 1์ˆœ์œ„๋Š” ์‚ฌํ›„ํ•ฉ๊ฒฉ(gated)** ์ž…๋‹ˆ๋‹ค. +- mode pool: `positive` ยท scoring: `band_proximity_p25_p75` + +### ํ›„๋ณด 4์ข… +- **โ‘  ์‚ฌํ›„ํ•ฉ๊ฒฉ 1์œ„ (apply: gated)**: ์—†์Œ +- **โ‘ก ์•ˆ์ • 1์œ„ (apply: stable)**: ์—†์Œ +- **โ‘ข mode_combo (apply: mode)**: ์—†์Œ (๋ฏธ์‚ฐ์ถœยท๊ตฌ JSON) +- **โ‘ฃ mode Top10 1์œ„ (apply: consensus ยท ๋ฐด๋“œ ์ „ํ˜• trial)**: ์—†์Œ +- mode Top10 meta: pool 0๊ฑด ยท ์ถ• 0๊ฐœ + +### ์ถ”์ฒœ (์ž๋™ ยท confirm ํ•„์ˆ˜) +1. **์‚ฌํ›„ํ•ฉ๊ฒฉ 0๊ฑด โ†’ DB ์ ์šฉ ๋น„๊ถŒ์žฅ.** ํ˜„ํ–‰ DB ์œ ์ง€ + ์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑยท๊ธฐ๊ฐ„ ์žฌ๊ฒ€์ฆ. +- โš  ์•ˆ์ • ๊ฒŒ์ดํŠธ 0๊ฑด โ†’ ์•ˆ์ • Top์€ **์ ์ˆ˜์ˆœ ํด๋ฐฑ** (์•ˆ์ • ๊ฒŒ์ดํŠธ 0๊ฑด โ†’ ํ•™์Šตํ’€ ์•ˆ์ •์ ์ˆ˜์ˆœ TopN (๋งˆ์ด๋„ˆ์Šค PnL ํฌํ•จ ยท ์ƒ๋Œ€๋น„๊ต)) + +## ์ด์ „ ์žฅ์—์„œ๋Š” +- ์‹ค๋งค ๋™๊ธฐ๊ฐ„ ์ฒญ์‚ฐ 13๊ฑด ยท ์Šน๋ฅ  31% ยท ํ•ฉ์‚ฐ PnL -34,618์› (๋ฐฑํ…Œ Optuna์™€ ์ˆซ์ž ๋‹ฌ๋ผ๋„ ์ •์ƒ โ€” ๊ณ ์ŠคํŠธยท์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑ ๊ฒฝ๋กœ ์ฐจ์ด). +- ์ด ๊ธฐ๊ฐ„ ๋ฐฑํ…Œ์—์„œ๋Š” **์œ ์˜๋ฏธํ•œ ํ†ต๊ณผ ์กฐํ•ฉ์ด ๊ฑฐ์˜ ์—†์—ˆ์Šต๋‹ˆ๋‹ค.** ์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑยท์†์ ˆยท์‹œ๊ฐ„์ฐฝ์„ ๋จผ์ € ์ ๊ฒ€ํ•˜์„ธ์š” (๋ŒํŒŒ 0๊ฑด์ด๋ฉด ํŠนํžˆ). + +## ์•ž์œผ๋กœ ์žฅ์—์„œ๋Š” +- **1~2์ผ Optuna best๋ฅผ ๋ฐ”๋กœ ์‹ค๋งค์— ๋„ฃ์ง€ ๋งˆ์„ธ์š”.** ๋‹ค์ผ(โ‰ฅ5๊ฑฐ๋ž˜์ผ) ์žฌ๊ฒ€์ฆยท์›น๋ฐฑํ…Œ 1ํšŒ ํ›„ ๊ฒ€ํ† . +- ์ ์šฉ ์‹œ์—๋Š” `results_gated` ํ›„๋ณด๋งŒ. ํƒ์ƒ‰์šฉ best(objective)์™€ ๋‹ค๋ฅผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. +- ์žฅ์ด ์ข์•„์ง€๊ฑฐ๋‚˜ ๋ณ€๋™์„ฑ์ด ์ปค์ง€๋ฉด: ์†์ ˆยทํŠธ๋ ˆ์ผยท์‹œ๊ฐ„์ฐฝ์ด ๋จผ์ € ๊นจ์ง‘๋‹ˆ๋‹ค. ์Šน๋ฅ  ์ž๋ž‘๋ณด๋‹ค **์†์ ˆ์ด ์‚ด์•„ ์žˆ๋Š”์ง€**๋ฅผ ๋ณด์„ธ์š”. +- ํ˜„์žฌ ์‚ฌํ›„ํ•ฉ๊ฒฉ 0๊ฑด โ†’ ํŒŒ๋ผ๋ฏธํ„ฐ ์œ ์ง€(ํ˜„ํ–‰ DB) + ์œ ๋‹ˆ๋ฒ„์Šค/๋ฐ์ดํ„ฐ ์ ๊ฒ€์ด ์šฐ์„ ์ž…๋‹ˆ๋‹ค. + +_์ƒ์„ฑ: 2026-09-05 01:24:03 (rule)_ + +## AI ์ฝ”๋ฉ˜ํŠธ (์ด์ „ ์žฅ / ์•ž์œผ๋กœ ์žฅ) [gemini] + +**์ด์ „ ์žฅ์—์„œ๋Š”** +์ด๋ฒˆ Optuna๋Š” 1๊ฑฐ๋ž˜์ผ ๊ธฐ๋ฐ˜ ํƒ์ƒ‰์œผ๋กœ ๊ณผ์ ํ•ฉ ์œ„ํ—˜ 73%์— ํ‘œ๋ณธ์ด ๋ถ€์กฑ(min_trades=2 ๋ฏธ๋‹ฌ, ํ•ฉ๊ฒฉ 0๊ฑด)ํ•˜์—ฌ ์œ ์˜๋ฏธํ•œ ์ „๋žต์ด ์—†์Šต๋‹ˆ๋‹ค. ์‹ค์ œ ๋งค๋งค ๊ธฐ๋ก ๋˜ํ•œ ์ข‹์ง€ ์•Š์•„ ๋ฐฑํ…Œ์ŠคํŠธ์™€ ์‹ค๋งค ๊ดด๋ฆฌ๋ฅผ ๋ณด์˜€์Šต๋‹ˆ๋‹ค. ํ˜„ ํŒŒ๋ผ๋ฏธํ„ฐ, ์œ ๋‹ˆ๋ฒ„์Šค, ํ‹ฑ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฉด๋ฐ€ํžˆ ์žฌ๊ฒ€ํ† ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. + +**์•ž์œผ๋กœ ์žฅ์—์„œ๋Š”** +๋‹จ์ผ ์žฅ ๊ฒฐ๊ณผ๋Š” ๊ณผ์ ํ•ฉ ๋ฐ ํ‘œ๋ณธ ๋ถ€์กฑ ์œ„ํ—˜์ด ์ปค ์‹ค๋งค ์ ์šฉ์€ ๊ธˆ๋ฌผ์ž…๋‹ˆ๋‹ค. ์•ˆ์ •์  ์ „๋žต์„ ์œ„ํ•ด ์ตœ์†Œ 5๊ฑฐ๋ž˜์ผ ์ด์ƒ ๋‹ค์ผ ๊ฒ€์ฆ๊ณผ ์›น๋ฐฑํ…Œ์ŠคํŠธ๋ฅผ ํ•„ํžˆ ๊ฑฐ์ณ์•ผ ํ•ฉ๋‹ˆ๋‹ค. 'mode Top10'์€ ์ต์ ˆ ๋Œ€ํ‘œ๊ฐ€ ์•„๋‹ˆ๋ฉฐ, ์ ์šฉ ๊ธฐ์ค€ '์‚ฌํ›„ํ•ฉ๊ฒฉ' ํ›„๋ณด๊ฐ€ ์—†์œผ๋‹ˆ ํ˜„ํ–‰ DB ์œ ์ง€๊ฐ€ ์šฐ์„ ์ž…๋‹ˆ๋‹ค. ๊ณ ์ŠคํŠธํผ์ง€ ๋“ฑ ๋ฐฑํ…Œ์ŠคํŠธ์™€ ์‹ค๋งค ๊ดด๋ฆฌ๋Š” ์ƒ์กดํ•˜๋ฉฐ, ํ™•์ • ์ˆ˜์ต ์•ฝ์†์ด๋‚˜ ์ข…๋ชฉ ๋งค์ˆ˜๋ฅผ ๊ถŒํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์†์ ˆ ์œ ํšจ์„ฑ์„ ์ƒ์‹œ ์ ๊ฒ€ํ•˜์„ธ์š”. diff --git a/kis_trader/backtest/results/optuna_breakout_tpe_20260905_012542.briefing.md b/kis_trader/backtest/results/optuna_breakout_tpe_20260905_012542.briefing.md new file mode 100644 index 0000000..f9dc518 --- /dev/null +++ b/kis_trader/backtest/results/optuna_breakout_tpe_20260905_012542.briefing.md @@ -0,0 +1,49 @@ +# Optuna ๋ธŒ๋ฆฌํ•‘ โ€” ๋ŒํŒŒ (tpe) +๊ธฐ๊ฐ„: 2026-09-04 ~ 2026-09-04 (๊ฑฐ๋ž˜์ผโ‰ˆ1์ผ) ยท trials 200/200 +ํƒ์ƒ‰ ๊ฒŒ์ดํŠธ: WRโ‰ฅ0% PFโ‰ฅ0 ยท min_tradesโ‰ฅ2 | ํ›„๋ณด ๊ฒŒ์ดํŠธ: WRโ‰ฅ40% PFโ‰ฅ1 ยท min_tradesโ‰ฅ2 +- min_trades=2: **ํ•ฉ๊ฒฉ ์ธ์ • ์ตœ์†Œ ๊ฑฐ๋ž˜ ๊ฑด์ˆ˜**(ํ‘œ๋ณธ ๋ถ€์กฑยท์šฐ์—ฐ ์Šน๋ฅ  ๋ฐฉ์ง€). ์ด๋ณด๋‹ค ์ ์€ ์กฐํ•ฉ์€ ํ•™์Šต/ํ›„๋ณด ์ง‘๊ณ„์—์„œ ์ œ์™ธ๋ฉ๋‹ˆ๋‹ค. +ํ•™์Šต์šฉ ํ†ต๊ณผ 0๊ฑด ยท ์‚ฌํ›„ํ•ฉ๊ฒฉ(results_gated) 0๊ฑด + +## ๊ณผ์ ํ•ฉยท์ ์šฉ ๊ฐ€๋Šฅ๋„ (ํœด๋ฆฌ์Šคํ‹ฑ) +- **๊ณผ์ ํ•ฉ ์œ„ํ—˜ 73.0%** ยท **์ ์šฉ ๊ฐ€๋Šฅ๋„ 27.0%** ยท ํŒ์ •: **๋น„๊ถŒ์žฅ** โ€” ๊ณผ์ ํ•ฉยทํ‘œ๋ณธ๋ถ€์กฑ ์œ„ํ—˜ ๋†’์Œ โ€” ์‹ค๋งค DB ์ฆ‰์‹œ ์ ์šฉ ๋น„๊ถŒ์žฅ + - ํ‘œ๋ณธ ์žฅ์ผ: +40.0p โ€” ๊ฑฐ๋ž˜์ผโ‰ˆ1์ผ โ€” ๋‹จ์ผ ์žฅ ๊ณผ์ ํ•ฉ ์œ„ํ—˜ ์ตœ๋Œ€ + - ๊ฑฐ๋ž˜ ํ‘œ๋ณธ: +25.0p โ€” ํ†ต๊ณผ ํ›„๋ณด ์—†์Œ โ€” ์ ์šฉ ๋ถˆ๊ฐ€ + - ์Šน๋ฅ ยทPF ์ด์ƒ์น˜: +0.0p โ€” ์ด์ƒ์น˜ ์—†์Œ + - ๊ฒŒ์ดํŠธ ์ปค๋ฒ„: +8.0p โ€” ํ•™์Šตยทgated ๋ชจ๋‘ ๋น„์–ด ์žˆ์Œ + - PnL ๊ณ ์›: +0.0p โ€” ๊ณ ์› ํŒ์ • ์Šคํ‚ต +- _์ฐธ๊ณ : ๊ณผ์ ํ•ฉ%๋Š” ๊ต์ฐจ๊ฒ€์ฆ ์ ์ˆ˜๊ฐ€ ์•„๋‹ˆ๋ผ ํ‘œ๋ณธยท์ด์ƒ์น˜ยท๊ณ ์› ํœด๋ฆฌ์Šคํ‹ฑ์ž…๋‹ˆ๋‹ค. ์ ์šฉ ๊ฐ€๋Šฅ๋„%=100โˆ’๊ณผ์ ํ•ฉ์œ„ํ—˜%. DB ์ ์šฉ ๋ฒ„ํŠผ ํ™œ์„ฑ ์กฐ๊ฑด(gated PnL>0)๊ณผ๋Š” ๋ณ„๊ฐœ์ž…๋‹ˆ๋‹ค._ + +## ์ตœ์ข… ์„ ํƒ ํ›„๋ณด (๊ทœ์น™ ยท DB ์ ์šฉ ์ „ ํ™•์ธ) +- ์•„๋ž˜๋Š” **์—ญํ• ์ด ๋‹ค๋ฅธ** 4์ข… ํ›„๋ณด์ž…๋‹ˆ๋‹ค. mode Top10 1์œ„ โ‰  ์ต์ ˆ ๋Œ€ํ‘œ ยท **DB 1์ˆœ์œ„๋Š” ์‚ฌํ›„ํ•ฉ๊ฒฉ(gated)** ์ž…๋‹ˆ๋‹ค. +- mode pool: `positive` ยท scoring: `band_proximity_p25_p75` + +### ํ›„๋ณด 4์ข… +- **โ‘  ์‚ฌํ›„ํ•ฉ๊ฒฉ 1์œ„ (apply: gated)**: ์—†์Œ +- **โ‘ก ์•ˆ์ • 1์œ„ (apply: stable)**: ์—†์Œ +- **โ‘ข mode_combo (apply: mode)**: ์—†์Œ (๋ฏธ์‚ฐ์ถœยท๊ตฌ JSON) +- **โ‘ฃ mode Top10 1์œ„ (apply: consensus ยท ๋ฐด๋“œ ์ „ํ˜• trial)**: ์—†์Œ +- mode Top10 meta: pool 0๊ฑด ยท ์ถ• 0๊ฐœ + +### ์ถ”์ฒœ (์ž๋™ ยท confirm ํ•„์ˆ˜) +1. **์‚ฌํ›„ํ•ฉ๊ฒฉ 0๊ฑด โ†’ DB ์ ์šฉ ๋น„๊ถŒ์žฅ.** ํ˜„ํ–‰ DB ์œ ์ง€ + ์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑยท๊ธฐ๊ฐ„ ์žฌ๊ฒ€์ฆ. +- โš  ์•ˆ์ • ๊ฒŒ์ดํŠธ 0๊ฑด โ†’ ์•ˆ์ • Top์€ **์ ์ˆ˜์ˆœ ํด๋ฐฑ** (์•ˆ์ • ๊ฒŒ์ดํŠธ 0๊ฑด โ†’ ํ•™์Šตํ’€ ์•ˆ์ •์ ์ˆ˜์ˆœ TopN (๋งˆ์ด๋„ˆ์Šค PnL ํฌํ•จ ยท ์ƒ๋Œ€๋น„๊ต)) + +## ์ด์ „ ์žฅ์—์„œ๋Š” +- ์‹ค๋งค ๋™๊ธฐ๊ฐ„ ์ฒญ์‚ฐ 13๊ฑด ยท ์Šน๋ฅ  31% ยท ํ•ฉ์‚ฐ PnL -34,618์› (๋ฐฑํ…Œ Optuna์™€ ์ˆซ์ž ๋‹ฌ๋ผ๋„ ์ •์ƒ โ€” ๊ณ ์ŠคํŠธยท์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑ ๊ฒฝ๋กœ ์ฐจ์ด). +- ์ด ๊ธฐ๊ฐ„ ๋ฐฑํ…Œ์—์„œ๋Š” **์œ ์˜๋ฏธํ•œ ํ†ต๊ณผ ์กฐํ•ฉ์ด ๊ฑฐ์˜ ์—†์—ˆ์Šต๋‹ˆ๋‹ค.** ์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑยท์†์ ˆยท์‹œ๊ฐ„์ฐฝ์„ ๋จผ์ € ์ ๊ฒ€ํ•˜์„ธ์š” (๋ŒํŒŒ 0๊ฑด์ด๋ฉด ํŠนํžˆ). + +## ์•ž์œผ๋กœ ์žฅ์—์„œ๋Š” +- **1~2์ผ Optuna best๋ฅผ ๋ฐ”๋กœ ์‹ค๋งค์— ๋„ฃ์ง€ ๋งˆ์„ธ์š”.** ๋‹ค์ผ(โ‰ฅ5๊ฑฐ๋ž˜์ผ) ์žฌ๊ฒ€์ฆยท์›น๋ฐฑํ…Œ 1ํšŒ ํ›„ ๊ฒ€ํ† . +- ์ ์šฉ ์‹œ์—๋Š” `results_gated` ํ›„๋ณด๋งŒ. ํƒ์ƒ‰์šฉ best(objective)์™€ ๋‹ค๋ฅผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. +- ์žฅ์ด ์ข์•„์ง€๊ฑฐ๋‚˜ ๋ณ€๋™์„ฑ์ด ์ปค์ง€๋ฉด: ์†์ ˆยทํŠธ๋ ˆ์ผยท์‹œ๊ฐ„์ฐฝ์ด ๋จผ์ € ๊นจ์ง‘๋‹ˆ๋‹ค. ์Šน๋ฅ  ์ž๋ž‘๋ณด๋‹ค **์†์ ˆ์ด ์‚ด์•„ ์žˆ๋Š”์ง€**๋ฅผ ๋ณด์„ธ์š”. +- ํ˜„์žฌ ์‚ฌํ›„ํ•ฉ๊ฒฉ 0๊ฑด โ†’ ํŒŒ๋ผ๋ฏธํ„ฐ ์œ ์ง€(ํ˜„ํ–‰ DB) + ์œ ๋‹ˆ๋ฒ„์Šค/๋ฐ์ดํ„ฐ ์ ๊ฒ€์ด ์šฐ์„ ์ž…๋‹ˆ๋‹ค. + +_์ƒ์„ฑ: 2026-09-05 01:25:42 (rule)_ + +## AI ์ฝ”๋ฉ˜ํŠธ (์ด์ „ ์žฅ / ์•ž์œผ๋กœ ์žฅ) [gemini] + +**์ด์ „ ์žฅ์—์„œ๋Š”** +์ง€๋‚œ 1์ผ๊ฐ„์˜ Optuna ๋ฐฑํ…Œ์ŠคํŠธ๋Š” ์œ ์˜๋ฏธํ•œ ํ†ต๊ณผ ์กฐํ•ฉ์ด 0๊ฑด์œผ๋กœ, ์‹ฌ๊ฐํ•œ ๊ณผ์ ํ•ฉ ๋ฐ ํ‘œ๋ณธ ๋ถ€์กฑ ์œ„ํ—˜์„ ๋ณด์˜€์Šต๋‹ˆ๋‹ค. ์‹ค๋งค ๋™๊ธฐ๊ฐ„ PnL์ด ๋ฐฑํ…Œ์™€ ๋‹ค๋ฅธ ์ (๊ณ ์ŠคํŠธํผ์ง€ ๋“ฑ) ์—ญ์‹œ ์ „๋žต์ด ํ˜„์‹ค์—์„œ ๋‹ค๋ฅด๊ฒŒ ์ž‘๋™ํ•  ์ˆ˜ ์žˆ์Œ์„ ๋ถ„๋ช…ํžˆ ๊ฒฝ๊ณ ํ•ฉ๋‹ˆ๋‹ค. + +**์•ž์œผ๋กœ ์žฅ์—์„œ๋Š”** +์ด๋ฒˆ ๊ฒฐ๊ณผ๋Š” '๋น„๊ถŒ์žฅ' ํŒ์ •์ด๋ฏ€๋กœ, 1~2์ผ์น˜ ์ „๋žต์„ ์ฆ‰์‹œ ์‹ค๋งค์— ์ ์šฉํ•ด์„  ์•ˆ ๋ฉ๋‹ˆ๋‹ค. ๋ฐ˜๋“œ์‹œ 5๊ฑฐ๋ž˜์ผ ์ด์ƒ ๋‹ค์ผ ๊ฒ€์ฆ์„ ๊ฑฐ์น˜๊ณ , `results_gated`๋œ ํ›„๋ณด๋งŒ ์‹ ์ค‘ํžˆ ๊ฒ€ํ† ํ•˜์„ธ์š”. DB 1์ˆœ์œ„๋Š” ์‚ฌํ›„ํ•ฉ๊ฒฉ์ด๋ฉฐ, `mode Top10 1์œ„`๋ฅผ ์ต์ ˆ ๋Œ€ํ‘œ๋กœ ๋‹จ์ •ํ•ด์„  ์•ˆ ๋ฉ๋‹ˆ๋‹ค. ํ˜„ํ–‰ DB๋ฅผ ์œ ์ง€ํ•˜๋ฉฐ ์œ ๋‹ˆ๋ฒ„์Šคยท๋ฐ์ดํ„ฐ๋ฅผ ์žฌ์ ๊ฒ€ํ•˜๋Š” ๊ฒƒ์ด ์šฐ์„ ์ž…๋‹ˆ๋‹ค. diff --git a/kis_trader/backtest/results/optuna_breakout_tpe_20260905_012701.briefing.md b/kis_trader/backtest/results/optuna_breakout_tpe_20260905_012701.briefing.md new file mode 100644 index 0000000..39b4971 --- /dev/null +++ b/kis_trader/backtest/results/optuna_breakout_tpe_20260905_012701.briefing.md @@ -0,0 +1,49 @@ +# Optuna ๋ธŒ๋ฆฌํ•‘ โ€” ๋ŒํŒŒ (tpe) +๊ธฐ๊ฐ„: 2026-09-04 ~ 2026-09-04 (๊ฑฐ๋ž˜์ผโ‰ˆ1์ผ) ยท trials 200/200 +ํƒ์ƒ‰ ๊ฒŒ์ดํŠธ: WRโ‰ฅ0% PFโ‰ฅ0 ยท min_tradesโ‰ฅ2 | ํ›„๋ณด ๊ฒŒ์ดํŠธ: WRโ‰ฅ40% PFโ‰ฅ1 ยท min_tradesโ‰ฅ2 +- min_trades=2: **ํ•ฉ๊ฒฉ ์ธ์ • ์ตœ์†Œ ๊ฑฐ๋ž˜ ๊ฑด์ˆ˜**(ํ‘œ๋ณธ ๋ถ€์กฑยท์šฐ์—ฐ ์Šน๋ฅ  ๋ฐฉ์ง€). ์ด๋ณด๋‹ค ์ ์€ ์กฐํ•ฉ์€ ํ•™์Šต/ํ›„๋ณด ์ง‘๊ณ„์—์„œ ์ œ์™ธ๋ฉ๋‹ˆ๋‹ค. +ํ•™์Šต์šฉ ํ†ต๊ณผ 0๊ฑด ยท ์‚ฌํ›„ํ•ฉ๊ฒฉ(results_gated) 0๊ฑด + +## ๊ณผ์ ํ•ฉยท์ ์šฉ ๊ฐ€๋Šฅ๋„ (ํœด๋ฆฌ์Šคํ‹ฑ) +- **๊ณผ์ ํ•ฉ ์œ„ํ—˜ 73.0%** ยท **์ ์šฉ ๊ฐ€๋Šฅ๋„ 27.0%** ยท ํŒ์ •: **๋น„๊ถŒ์žฅ** โ€” ๊ณผ์ ํ•ฉยทํ‘œ๋ณธ๋ถ€์กฑ ์œ„ํ—˜ ๋†’์Œ โ€” ์‹ค๋งค DB ์ฆ‰์‹œ ์ ์šฉ ๋น„๊ถŒ์žฅ + - ํ‘œ๋ณธ ์žฅ์ผ: +40.0p โ€” ๊ฑฐ๋ž˜์ผโ‰ˆ1์ผ โ€” ๋‹จ์ผ ์žฅ ๊ณผ์ ํ•ฉ ์œ„ํ—˜ ์ตœ๋Œ€ + - ๊ฑฐ๋ž˜ ํ‘œ๋ณธ: +25.0p โ€” ํ†ต๊ณผ ํ›„๋ณด ์—†์Œ โ€” ์ ์šฉ ๋ถˆ๊ฐ€ + - ์Šน๋ฅ ยทPF ์ด์ƒ์น˜: +0.0p โ€” ์ด์ƒ์น˜ ์—†์Œ + - ๊ฒŒ์ดํŠธ ์ปค๋ฒ„: +8.0p โ€” ํ•™์Šตยทgated ๋ชจ๋‘ ๋น„์–ด ์žˆ์Œ + - PnL ๊ณ ์›: +0.0p โ€” ๊ณ ์› ํŒ์ • ์Šคํ‚ต +- _์ฐธ๊ณ : ๊ณผ์ ํ•ฉ%๋Š” ๊ต์ฐจ๊ฒ€์ฆ ์ ์ˆ˜๊ฐ€ ์•„๋‹ˆ๋ผ ํ‘œ๋ณธยท์ด์ƒ์น˜ยท๊ณ ์› ํœด๋ฆฌ์Šคํ‹ฑ์ž…๋‹ˆ๋‹ค. ์ ์šฉ ๊ฐ€๋Šฅ๋„%=100โˆ’๊ณผ์ ํ•ฉ์œ„ํ—˜%. DB ์ ์šฉ ๋ฒ„ํŠผ ํ™œ์„ฑ ์กฐ๊ฑด(gated PnL>0)๊ณผ๋Š” ๋ณ„๊ฐœ์ž…๋‹ˆ๋‹ค._ + +## ์ตœ์ข… ์„ ํƒ ํ›„๋ณด (๊ทœ์น™ ยท DB ์ ์šฉ ์ „ ํ™•์ธ) +- ์•„๋ž˜๋Š” **์—ญํ• ์ด ๋‹ค๋ฅธ** 4์ข… ํ›„๋ณด์ž…๋‹ˆ๋‹ค. mode Top10 1์œ„ โ‰  ์ต์ ˆ ๋Œ€ํ‘œ ยท **DB 1์ˆœ์œ„๋Š” ์‚ฌํ›„ํ•ฉ๊ฒฉ(gated)** ์ž…๋‹ˆ๋‹ค. +- mode pool: `positive` ยท scoring: `band_proximity_p25_p75` + +### ํ›„๋ณด 4์ข… +- **โ‘  ์‚ฌํ›„ํ•ฉ๊ฒฉ 1์œ„ (apply: gated)**: ์—†์Œ +- **โ‘ก ์•ˆ์ • 1์œ„ (apply: stable)**: ์—†์Œ +- **โ‘ข mode_combo (apply: mode)**: ์—†์Œ (๋ฏธ์‚ฐ์ถœยท๊ตฌ JSON) +- **โ‘ฃ mode Top10 1์œ„ (apply: consensus ยท ๋ฐด๋“œ ์ „ํ˜• trial)**: ์—†์Œ +- mode Top10 meta: pool 0๊ฑด ยท ์ถ• 0๊ฐœ + +### ์ถ”์ฒœ (์ž๋™ ยท confirm ํ•„์ˆ˜) +1. **์‚ฌํ›„ํ•ฉ๊ฒฉ 0๊ฑด โ†’ DB ์ ์šฉ ๋น„๊ถŒ์žฅ.** ํ˜„ํ–‰ DB ์œ ์ง€ + ์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑยท๊ธฐ๊ฐ„ ์žฌ๊ฒ€์ฆ. +- โš  ์•ˆ์ • ๊ฒŒ์ดํŠธ 0๊ฑด โ†’ ์•ˆ์ • Top์€ **์ ์ˆ˜์ˆœ ํด๋ฐฑ** (์•ˆ์ • ๊ฒŒ์ดํŠธ 0๊ฑด โ†’ ํ•™์Šตํ’€ ์•ˆ์ •์ ์ˆ˜์ˆœ TopN (๋งˆ์ด๋„ˆ์Šค PnL ํฌํ•จ ยท ์ƒ๋Œ€๋น„๊ต)) + +## ์ด์ „ ์žฅ์—์„œ๋Š” +- ์‹ค๋งค ๋™๊ธฐ๊ฐ„ ์ฒญ์‚ฐ 13๊ฑด ยท ์Šน๋ฅ  31% ยท ํ•ฉ์‚ฐ PnL -34,618์› (๋ฐฑํ…Œ Optuna์™€ ์ˆซ์ž ๋‹ฌ๋ผ๋„ ์ •์ƒ โ€” ๊ณ ์ŠคํŠธยท์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑ ๊ฒฝ๋กœ ์ฐจ์ด). +- ์ด ๊ธฐ๊ฐ„ ๋ฐฑํ…Œ์—์„œ๋Š” **์œ ์˜๋ฏธํ•œ ํ†ต๊ณผ ์กฐํ•ฉ์ด ๊ฑฐ์˜ ์—†์—ˆ์Šต๋‹ˆ๋‹ค.** ์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑยท์†์ ˆยท์‹œ๊ฐ„์ฐฝ์„ ๋จผ์ € ์ ๊ฒ€ํ•˜์„ธ์š” (๋ŒํŒŒ 0๊ฑด์ด๋ฉด ํŠนํžˆ). + +## ์•ž์œผ๋กœ ์žฅ์—์„œ๋Š” +- **1~2์ผ Optuna best๋ฅผ ๋ฐ”๋กœ ์‹ค๋งค์— ๋„ฃ์ง€ ๋งˆ์„ธ์š”.** ๋‹ค์ผ(โ‰ฅ5๊ฑฐ๋ž˜์ผ) ์žฌ๊ฒ€์ฆยท์›น๋ฐฑํ…Œ 1ํšŒ ํ›„ ๊ฒ€ํ† . +- ์ ์šฉ ์‹œ์—๋Š” `results_gated` ํ›„๋ณด๋งŒ. ํƒ์ƒ‰์šฉ best(objective)์™€ ๋‹ค๋ฅผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. +- ์žฅ์ด ์ข์•„์ง€๊ฑฐ๋‚˜ ๋ณ€๋™์„ฑ์ด ์ปค์ง€๋ฉด: ์†์ ˆยทํŠธ๋ ˆ์ผยท์‹œ๊ฐ„์ฐฝ์ด ๋จผ์ € ๊นจ์ง‘๋‹ˆ๋‹ค. ์Šน๋ฅ  ์ž๋ž‘๋ณด๋‹ค **์†์ ˆ์ด ์‚ด์•„ ์žˆ๋Š”์ง€**๋ฅผ ๋ณด์„ธ์š”. +- ํ˜„์žฌ ์‚ฌํ›„ํ•ฉ๊ฒฉ 0๊ฑด โ†’ ํŒŒ๋ผ๋ฏธํ„ฐ ์œ ์ง€(ํ˜„ํ–‰ DB) + ์œ ๋‹ˆ๋ฒ„์Šค/๋ฐ์ดํ„ฐ ์ ๊ฒ€์ด ์šฐ์„ ์ž…๋‹ˆ๋‹ค. + +_์ƒ์„ฑ: 2026-09-05 01:27:01 (rule)_ + +## AI ์ฝ”๋ฉ˜ํŠธ (์ด์ „ ์žฅ / ์•ž์œผ๋กœ ์žฅ) [gemini] + +์ด์ „ ์žฅ์—์„œ๋Š” +๋‹จ์ผ ์žฅ(1์ผ) ๋ฐฑํ…Œ์ŠคํŠธ ๊ฒฐ๊ณผ, ๊ณผ์ ํ•ฉ ์œ„ํ—˜ 73%๋กœ ๋น„๊ถŒ์žฅ ํŒ์ •์ž…๋‹ˆ๋‹ค. ํ•™์Šต ๋ฐ ์‚ฌํ›„ํ•ฉ๊ฒฉ๋œ ์กฐํ•ฉ์ด 0๊ฑด์ด๋ฉฐ, ํ‘œ๋ณธ ๋ถ€์กฑ ์œ„ํ—˜์ด ๋งค์šฐ ๋†’์Šต๋‹ˆ๋‹ค. ์‹ค๋งค ์—ญ์‹œ ๋™๊ธฐ๊ฐ„ -34,618์› ์†์‹ค๋กœ, ๋ฐฑํ…Œ์ŠคํŠธ์™€ ์‹ค๋งค ๊ดด๋ฆฌ(๊ณ ์ŠคํŠธํผ์ง€ ๋“ฑ)๋ฅผ ์žฌํ™•์ธํ–ˆ์Šต๋‹ˆ๋‹ค. ์œ ๋‹ˆ๋ฒ„์Šค, ํ‹ฑ ๋ฐ์ดํ„ฐ ๋“ฑ ์ „๋ฐ˜์ ์ธ ์žฌ์ ๊ฒ€์ด ์‹œ๊ธ‰ํ•ฉ๋‹ˆ๋‹ค. + +์•ž์œผ๋กœ ์žฅ์—์„œ๋Š” +์ด๋ฒˆ 1์ผ ๋ฐฑํ…Œ์ŠคํŠธ ๊ฒฐ๊ณผ๋Š” ์ฆ‰์‹œ ์‹ค๋งค ์ ์šฉ์ด ๋ถˆ๊ฐ€ํ•ฉ๋‹ˆ๋‹ค. ๊ณผ์ ํ•ฉยทํ‘œ๋ณธ๋ถ€์กฑ ์œ„ํ—˜์ด ๋†’์•„ ์šฐ์—ฐํ•œ ๊ฒฐ๊ณผ์ผ ๊ฐ€๋Šฅ์„ฑ์ด ํฝ๋‹ˆ๋‹ค. `mode Top10 1์œ„`๊ฐ€ ์ต์ ˆ ๋Œ€ํ‘œ๊ฐ€ ์•„๋‹˜์„ ์ธ์ง€ํ•˜๊ณ , **DB 1์ˆœ์œ„์ธ ์‚ฌํ›„ํ•ฉ๊ฒฉ(gated)๋œ ํ›„๋ณด๋งŒ** ๋‹ค์ผ(โ‰ฅ5๊ฑฐ๋ž˜์ผ) ์žฌ๊ฒ€์ฆ ํ›„ ์ ์šฉ์„ ๊ฒ€ํ† ํ•˜์„ธ์š”. ํ˜„์žฌ๋Š” ํ˜„ํ–‰ DB ์œ ์ง€์™€ ๋ฐ์ดํ„ฐ ์ ๊ฒ€์ด ์šฐ์„ ์ž…๋‹ˆ๋‹ค. diff --git a/kis_trader/backtest/results/optuna_breakout_tpe_20260905_012809.briefing.md b/kis_trader/backtest/results/optuna_breakout_tpe_20260905_012809.briefing.md new file mode 100644 index 0000000..5ad8e83 --- /dev/null +++ b/kis_trader/backtest/results/optuna_breakout_tpe_20260905_012809.briefing.md @@ -0,0 +1,49 @@ +# Optuna ๋ธŒ๋ฆฌํ•‘ โ€” ๋ŒํŒŒ (tpe) +๊ธฐ๊ฐ„: 2026-09-04 ~ 2026-09-04 (๊ฑฐ๋ž˜์ผโ‰ˆ1์ผ) ยท trials 200/200 +ํƒ์ƒ‰ ๊ฒŒ์ดํŠธ: WRโ‰ฅ0% PFโ‰ฅ0 ยท min_tradesโ‰ฅ2 | ํ›„๋ณด ๊ฒŒ์ดํŠธ: WRโ‰ฅ40% PFโ‰ฅ1 ยท min_tradesโ‰ฅ2 +- min_trades=2: **ํ•ฉ๊ฒฉ ์ธ์ • ์ตœ์†Œ ๊ฑฐ๋ž˜ ๊ฑด์ˆ˜**(ํ‘œ๋ณธ ๋ถ€์กฑยท์šฐ์—ฐ ์Šน๋ฅ  ๋ฐฉ์ง€). ์ด๋ณด๋‹ค ์ ์€ ์กฐํ•ฉ์€ ํ•™์Šต/ํ›„๋ณด ์ง‘๊ณ„์—์„œ ์ œ์™ธ๋ฉ๋‹ˆ๋‹ค. +ํ•™์Šต์šฉ ํ†ต๊ณผ 0๊ฑด ยท ์‚ฌํ›„ํ•ฉ๊ฒฉ(results_gated) 0๊ฑด + +## ๊ณผ์ ํ•ฉยท์ ์šฉ ๊ฐ€๋Šฅ๋„ (ํœด๋ฆฌ์Šคํ‹ฑ) +- **๊ณผ์ ํ•ฉ ์œ„ํ—˜ 73.0%** ยท **์ ์šฉ ๊ฐ€๋Šฅ๋„ 27.0%** ยท ํŒ์ •: **๋น„๊ถŒ์žฅ** โ€” ๊ณผ์ ํ•ฉยทํ‘œ๋ณธ๋ถ€์กฑ ์œ„ํ—˜ ๋†’์Œ โ€” ์‹ค๋งค DB ์ฆ‰์‹œ ์ ์šฉ ๋น„๊ถŒ์žฅ + - ํ‘œ๋ณธ ์žฅ์ผ: +40.0p โ€” ๊ฑฐ๋ž˜์ผโ‰ˆ1์ผ โ€” ๋‹จ์ผ ์žฅ ๊ณผ์ ํ•ฉ ์œ„ํ—˜ ์ตœ๋Œ€ + - ๊ฑฐ๋ž˜ ํ‘œ๋ณธ: +25.0p โ€” ํ†ต๊ณผ ํ›„๋ณด ์—†์Œ โ€” ์ ์šฉ ๋ถˆ๊ฐ€ + - ์Šน๋ฅ ยทPF ์ด์ƒ์น˜: +0.0p โ€” ์ด์ƒ์น˜ ์—†์Œ + - ๊ฒŒ์ดํŠธ ์ปค๋ฒ„: +8.0p โ€” ํ•™์Šตยทgated ๋ชจ๋‘ ๋น„์–ด ์žˆ์Œ + - PnL ๊ณ ์›: +0.0p โ€” ๊ณ ์› ํŒ์ • ์Šคํ‚ต +- _์ฐธ๊ณ : ๊ณผ์ ํ•ฉ%๋Š” ๊ต์ฐจ๊ฒ€์ฆ ์ ์ˆ˜๊ฐ€ ์•„๋‹ˆ๋ผ ํ‘œ๋ณธยท์ด์ƒ์น˜ยท๊ณ ์› ํœด๋ฆฌ์Šคํ‹ฑ์ž…๋‹ˆ๋‹ค. ์ ์šฉ ๊ฐ€๋Šฅ๋„%=100โˆ’๊ณผ์ ํ•ฉ์œ„ํ—˜%. DB ์ ์šฉ ๋ฒ„ํŠผ ํ™œ์„ฑ ์กฐ๊ฑด(gated PnL>0)๊ณผ๋Š” ๋ณ„๊ฐœ์ž…๋‹ˆ๋‹ค._ + +## ์ตœ์ข… ์„ ํƒ ํ›„๋ณด (๊ทœ์น™ ยท DB ์ ์šฉ ์ „ ํ™•์ธ) +- ์•„๋ž˜๋Š” **์—ญํ• ์ด ๋‹ค๋ฅธ** 4์ข… ํ›„๋ณด์ž…๋‹ˆ๋‹ค. mode Top10 1์œ„ โ‰  ์ต์ ˆ ๋Œ€ํ‘œ ยท **DB 1์ˆœ์œ„๋Š” ์‚ฌํ›„ํ•ฉ๊ฒฉ(gated)** ์ž…๋‹ˆ๋‹ค. +- mode pool: `positive` ยท scoring: `band_proximity_p25_p75` + +### ํ›„๋ณด 4์ข… +- **โ‘  ์‚ฌํ›„ํ•ฉ๊ฒฉ 1์œ„ (apply: gated)**: ์—†์Œ +- **โ‘ก ์•ˆ์ • 1์œ„ (apply: stable)**: ์—†์Œ +- **โ‘ข mode_combo (apply: mode)**: ์—†์Œ (๋ฏธ์‚ฐ์ถœยท๊ตฌ JSON) +- **โ‘ฃ mode Top10 1์œ„ (apply: consensus ยท ๋ฐด๋“œ ์ „ํ˜• trial)**: ์—†์Œ +- mode Top10 meta: pool 0๊ฑด ยท ์ถ• 0๊ฐœ + +### ์ถ”์ฒœ (์ž๋™ ยท confirm ํ•„์ˆ˜) +1. **์‚ฌํ›„ํ•ฉ๊ฒฉ 0๊ฑด โ†’ DB ์ ์šฉ ๋น„๊ถŒ์žฅ.** ํ˜„ํ–‰ DB ์œ ์ง€ + ์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑยท๊ธฐ๊ฐ„ ์žฌ๊ฒ€์ฆ. +- โš  ์•ˆ์ • ๊ฒŒ์ดํŠธ 0๊ฑด โ†’ ์•ˆ์ • Top์€ **์ ์ˆ˜์ˆœ ํด๋ฐฑ** (์•ˆ์ • ๊ฒŒ์ดํŠธ 0๊ฑด โ†’ ํ•™์Šตํ’€ ์•ˆ์ •์ ์ˆ˜์ˆœ TopN (๋งˆ์ด๋„ˆ์Šค PnL ํฌํ•จ ยท ์ƒ๋Œ€๋น„๊ต)) + +## ์ด์ „ ์žฅ์—์„œ๋Š” +- ์‹ค๋งค ๋™๊ธฐ๊ฐ„ ์ฒญ์‚ฐ 13๊ฑด ยท ์Šน๋ฅ  31% ยท ํ•ฉ์‚ฐ PnL -34,618์› (๋ฐฑํ…Œ Optuna์™€ ์ˆซ์ž ๋‹ฌ๋ผ๋„ ์ •์ƒ โ€” ๊ณ ์ŠคํŠธยท์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑ ๊ฒฝ๋กœ ์ฐจ์ด). +- ์ด ๊ธฐ๊ฐ„ ๋ฐฑํ…Œ์—์„œ๋Š” **์œ ์˜๋ฏธํ•œ ํ†ต๊ณผ ์กฐํ•ฉ์ด ๊ฑฐ์˜ ์—†์—ˆ์Šต๋‹ˆ๋‹ค.** ์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑยท์†์ ˆยท์‹œ๊ฐ„์ฐฝ์„ ๋จผ์ € ์ ๊ฒ€ํ•˜์„ธ์š” (๋ŒํŒŒ 0๊ฑด์ด๋ฉด ํŠนํžˆ). + +## ์•ž์œผ๋กœ ์žฅ์—์„œ๋Š” +- **1~2์ผ Optuna best๋ฅผ ๋ฐ”๋กœ ์‹ค๋งค์— ๋„ฃ์ง€ ๋งˆ์„ธ์š”.** ๋‹ค์ผ(โ‰ฅ5๊ฑฐ๋ž˜์ผ) ์žฌ๊ฒ€์ฆยท์›น๋ฐฑํ…Œ 1ํšŒ ํ›„ ๊ฒ€ํ† . +- ์ ์šฉ ์‹œ์—๋Š” `results_gated` ํ›„๋ณด๋งŒ. ํƒ์ƒ‰์šฉ best(objective)์™€ ๋‹ค๋ฅผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. +- ์žฅ์ด ์ข์•„์ง€๊ฑฐ๋‚˜ ๋ณ€๋™์„ฑ์ด ์ปค์ง€๋ฉด: ์†์ ˆยทํŠธ๋ ˆ์ผยท์‹œ๊ฐ„์ฐฝ์ด ๋จผ์ € ๊นจ์ง‘๋‹ˆ๋‹ค. ์Šน๋ฅ  ์ž๋ž‘๋ณด๋‹ค **์†์ ˆ์ด ์‚ด์•„ ์žˆ๋Š”์ง€**๋ฅผ ๋ณด์„ธ์š”. +- ํ˜„์žฌ ์‚ฌํ›„ํ•ฉ๊ฒฉ 0๊ฑด โ†’ ํŒŒ๋ผ๋ฏธํ„ฐ ์œ ์ง€(ํ˜„ํ–‰ DB) + ์œ ๋‹ˆ๋ฒ„์Šค/๋ฐ์ดํ„ฐ ์ ๊ฒ€์ด ์šฐ์„ ์ž…๋‹ˆ๋‹ค. + +_์ƒ์„ฑ: 2026-09-05 01:28:09 (rule)_ + +## AI ์ฝ”๋ฉ˜ํŠธ (์ด์ „ ์žฅ / ์•ž์œผ๋กœ ์žฅ) [gemini] + +## ์ด์ „ ์žฅ์—์„œ๋Š” +์ง€๋‚œ 9์›” 4์ผ ๋‹จ ํ•˜๋ฃจ์˜ ๋ฐฑํ…Œ์ŠคํŠธ ๊ฒฐ๊ณผ๋ฅผ ๊ฒ€ํ† ํ–ˆ์Šต๋‹ˆ๋‹ค. Optuna TPE ํƒ์ƒ‰ ๊ฒฐ๊ณผ, ํ•™์Šต์šฉ ํ†ต๊ณผ ์กฐํ•ฉ์€ ๋ฌผ๋ก , ์‹ค์ œ ์ ์šฉ ๊ฐ€๋Šฅํ•œ '์‚ฌํ›„ํ•ฉ๊ฒฉ(results_gated)' ์กฐํ•ฉ์ด ๋‹จ ํ•œ ๊ฑด๋„ ๋‚˜์˜ค์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. ์ด๋Š” ๋‹จ์ผ ๊ฑฐ๋ž˜์ผ์— ๋Œ€ํ•œ ๋ถ„์„์ด์—ˆ๊ธฐ์— ๊ณผ์ ํ•ฉ ์œ„ํ—˜์ด 73%๋กœ ๋งค์šฐ ๋†’์•˜๊ณ , ์ ์šฉ ๊ฐ€๋Šฅ์„ฑ์€ 27%์— ๋ถˆ๊ณผํ•˜์—ฌ '๋น„๊ถŒ์žฅ' ํŒ์ •์ด ๋‚ด๋ ค์กŒ์Šต๋‹ˆ๋‹ค. ์ด์ฒ˜๋Ÿผ ํ‘œ๋ณธ ๋ถ€์กฑ ํ™˜๊ฒฝ์—์„œ๋Š” ๋ฐฑํ…Œ์ŠคํŠธ ๊ฒฐ๊ณผ ์ž์ฒด๋ฅผ ์‹ ๋ขฐํ•˜๊ธฐ ์–ด๋ ต์Šต๋‹ˆ๋‹ค. ์‹ค๋งค์—์„œ๋Š” ํ•ด๋‹น ๊ธฐ๊ฐ„ ์†์‹ค์ด ๋ฐœ์ƒํ–ˆ์œผ๋‚˜, ๋ฐฑํ…Œ์ŠคํŠธ์—์„œ ์œ ์˜๋ฏธํ•œ ์กฐํ•ฉ์ด ์ „๋ฌดํ–ˆ๋‹ค๋Š” ์ ์€ ์œ ๋‹ˆ๋ฒ„์Šค, ํ‹ฑ ๋ฐ์ดํ„ฐ, ๋˜๋Š” ์ „๋žต ์ž์ฒด์˜ ์žฌ๊ฒ€ํ† ๊ฐ€ ์‹œ๊ธ‰ํ•จ์„ ์‹œ์‚ฌํ•ฉ๋‹ˆ๋‹ค. + +## ์•ž์œผ๋กœ ์žฅ์—์„œ๋Š” +์ด๋ฒˆ์ฒ˜๋Ÿผ ๊ทนํžˆ ์งง์€ ๊ธฐ๊ฐ„(๋‹จ์ผ ๊ฑฐ๋ž˜์ผ)์˜ Optuna ์ตœ์ ํ™” ๊ฒฐ๊ณผ๋ฅผ ์ฆ‰์‹œ ์‹ค๋งค์— ์ ์šฉํ•˜๋Š” ๊ฒƒ์€ ์ ˆ๋Œ€ ๊ธˆ๋ฌผ์ž…๋‹ˆ๋‹ค. ์ด๋Š” ํ‘œ๋ณธ ๋ถ€์กฑ๊ณผ ๊ณผ์ ํ•ฉ ์œ„ํ—˜์ด ์ตœ๋Œ€์น˜์— ๋‹ฌํ•œ ์ƒํƒœ์ด๋ฉฐ, ๋ฐฑํ…Œ์ŠคํŠธ์ƒ ์–ด๋– ํ•œ ๊ธ์ •์  ๊ฒฐ๊ณผ๊ฐ€ ๋‚˜์™”๋”๋ผ๋„ ์‹ค๋งค์—์„œ๋Š” ๋ฐฑํ…Œ์ŠคํŠธ์™€ ์‹ค๋งค ๊ฐ„ ๊ดด๋ฆฌ(๊ณ ์ŠคํŠธํผ์ง€ ๋“ฑ)๋กœ ์ธํ•ด ํฐ ์†์‹ค๋กœ ์ด์–ด์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. `mode Top10 1์œ„`๋Š” ๋‹จ์ˆœ ๋ฐด๋“œ ์ „ํ˜•์ผ ๋ฟ, ์‹ค์ œ ์ต์ ˆ์„ ๋Œ€ํ‘œํ•˜๋Š” '์‚ฌํ›„ํ•ฉ๊ฒฉ' ์กฐํ•ฉ์ด ์•„๋‹˜์„ ๋ช…์‹ฌํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ, ์ตœ์†Œ 5๊ฑฐ๋ž˜์ผ ์ด์ƒ์˜ ์ถฉ๋ถ„ํ•œ ๊ธฐ๊ฐ„ ๋™์•ˆ ์žฌ๊ฒ€์ฆ์„ ์ง„ํ–‰ํ•˜๊ณ , ์•ˆ์ •์„ฑ๊ณผ ๊ฒฌ๊ณ ์„ฑ์ด ํ™•๋ณด๋œ `์‚ฌํ›„ํ•ฉ๊ฒฉ(results_gated)` ์กฐํ•ฉ์ด ๋„์ถœ๋  ๋•Œ๊นŒ์ง€ ํ˜„ํ–‰ ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ์œ ์ง€ํ•˜๋ฉฐ ์œ ๋‹ˆ๋ฒ„์Šค ๋ฐ ๋ฐ์ดํ„ฐ ๊ฒ€์ฆ์— ์ง‘์ค‘ํ•ด ์ฃผ์‹œ๊ธฐ ๋ฐ”๋ž๋‹ˆ๋‹ค. ์ˆ˜์ต๋ฅ ๋ณด๋‹ค ์†์ ˆ๋งค ๋กœ์ง์ด ์‹œ์žฅ ๋ณ€ํ™”์— ์ž˜ ๋Œ€์‘ํ•˜๋Š”์ง€ ํ™•์ธํ•˜๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค. ํŠน์ • ์ข…๋ชฉ ๋งค์ˆ˜ ์ถ”์ฒœ์ด๋‚˜ ํ™•์ • ์ˆ˜์ต์€ ์•ฝ์†ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. diff --git a/kis_trader/backtest/results/optuna_breakout_tpe_20260905_012951.briefing.md b/kis_trader/backtest/results/optuna_breakout_tpe_20260905_012951.briefing.md new file mode 100644 index 0000000..4b9c50a --- /dev/null +++ b/kis_trader/backtest/results/optuna_breakout_tpe_20260905_012951.briefing.md @@ -0,0 +1,51 @@ +# Optuna ๋ธŒ๋ฆฌํ•‘ โ€” ๋ŒํŒŒ (tpe) +๊ธฐ๊ฐ„: 2026-09-04 ~ 2026-09-04 (๊ฑฐ๋ž˜์ผโ‰ˆ1์ผ) ยท trials 200/200 +ํƒ์ƒ‰ ๊ฒŒ์ดํŠธ: WRโ‰ฅ0% PFโ‰ฅ0 ยท min_tradesโ‰ฅ2 | ํ›„๋ณด ๊ฒŒ์ดํŠธ: WRโ‰ฅ40% PFโ‰ฅ1 ยท min_tradesโ‰ฅ2 +- min_trades=2: **ํ•ฉ๊ฒฉ ์ธ์ • ์ตœ์†Œ ๊ฑฐ๋ž˜ ๊ฑด์ˆ˜**(ํ‘œ๋ณธ ๋ถ€์กฑยท์šฐ์—ฐ ์Šน๋ฅ  ๋ฐฉ์ง€). ์ด๋ณด๋‹ค ์ ์€ ์กฐํ•ฉ์€ ํ•™์Šต/ํ›„๋ณด ์ง‘๊ณ„์—์„œ ์ œ์™ธ๋ฉ๋‹ˆ๋‹ค. +ํ•™์Šต์šฉ ํ†ต๊ณผ 0๊ฑด ยท ์‚ฌํ›„ํ•ฉ๊ฒฉ(results_gated) 0๊ฑด + +## ๊ณผ์ ํ•ฉยท์ ์šฉ ๊ฐ€๋Šฅ๋„ (ํœด๋ฆฌ์Šคํ‹ฑ) +- **๊ณผ์ ํ•ฉ ์œ„ํ—˜ 73.0%** ยท **์ ์šฉ ๊ฐ€๋Šฅ๋„ 27.0%** ยท ํŒ์ •: **๋น„๊ถŒ์žฅ** โ€” ๊ณผ์ ํ•ฉยทํ‘œ๋ณธ๋ถ€์กฑ ์œ„ํ—˜ ๋†’์Œ โ€” ์‹ค๋งค DB ์ฆ‰์‹œ ์ ์šฉ ๋น„๊ถŒ์žฅ + - ํ‘œ๋ณธ ์žฅ์ผ: +40.0p โ€” ๊ฑฐ๋ž˜์ผโ‰ˆ1์ผ โ€” ๋‹จ์ผ ์žฅ ๊ณผ์ ํ•ฉ ์œ„ํ—˜ ์ตœ๋Œ€ + - ๊ฑฐ๋ž˜ ํ‘œ๋ณธ: +25.0p โ€” ํ†ต๊ณผ ํ›„๋ณด ์—†์Œ โ€” ์ ์šฉ ๋ถˆ๊ฐ€ + - ์Šน๋ฅ ยทPF ์ด์ƒ์น˜: +0.0p โ€” ์ด์ƒ์น˜ ์—†์Œ + - ๊ฒŒ์ดํŠธ ์ปค๋ฒ„: +8.0p โ€” ํ•™์Šตยทgated ๋ชจ๋‘ ๋น„์–ด ์žˆ์Œ + - PnL ๊ณ ์›: +0.0p โ€” ๊ณ ์› ํŒ์ • ์Šคํ‚ต +- _์ฐธ๊ณ : ๊ณผ์ ํ•ฉ%๋Š” ๊ต์ฐจ๊ฒ€์ฆ ์ ์ˆ˜๊ฐ€ ์•„๋‹ˆ๋ผ ํ‘œ๋ณธยท์ด์ƒ์น˜ยท๊ณ ์› ํœด๋ฆฌ์Šคํ‹ฑ์ž…๋‹ˆ๋‹ค. ์ ์šฉ ๊ฐ€๋Šฅ๋„%=100โˆ’๊ณผ์ ํ•ฉ์œ„ํ—˜%. DB ์ ์šฉ ๋ฒ„ํŠผ ํ™œ์„ฑ ์กฐ๊ฑด(gated PnL>0)๊ณผ๋Š” ๋ณ„๊ฐœ์ž…๋‹ˆ๋‹ค._ + +## ์ตœ์ข… ์„ ํƒ ํ›„๋ณด (๊ทœ์น™ ยท DB ์ ์šฉ ์ „ ํ™•์ธ) +- ์•„๋ž˜๋Š” **์—ญํ• ์ด ๋‹ค๋ฅธ** 4์ข… ํ›„๋ณด์ž…๋‹ˆ๋‹ค. mode Top10 1์œ„ โ‰  ์ต์ ˆ ๋Œ€ํ‘œ ยท **DB 1์ˆœ์œ„๋Š” ์‚ฌํ›„ํ•ฉ๊ฒฉ(gated)** ์ž…๋‹ˆ๋‹ค. +- mode pool: `positive` ยท scoring: `band_proximity_p25_p75` + +### ํ›„๋ณด 4์ข… +- **โ‘  ์‚ฌํ›„ํ•ฉ๊ฒฉ 1์œ„ (apply: gated)**: ์—†์Œ +- **โ‘ก ์•ˆ์ • 1์œ„ (apply: stable)**: ์—†์Œ +- **โ‘ข mode_combo (apply: mode)**: ์—†์Œ (๋ฏธ์‚ฐ์ถœยท๊ตฌ JSON) +- **โ‘ฃ mode Top10 1์œ„ (apply: consensus ยท ๋ฐด๋“œ ์ „ํ˜• trial)**: ์—†์Œ +- mode Top10 meta: pool 0๊ฑด ยท ์ถ• 0๊ฐœ + +### ์ถ”์ฒœ (์ž๋™ ยท confirm ํ•„์ˆ˜) +1. **์‚ฌํ›„ํ•ฉ๊ฒฉ 0๊ฑด โ†’ DB ์ ์šฉ ๋น„๊ถŒ์žฅ.** ํ˜„ํ–‰ DB ์œ ์ง€ + ์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑยท๊ธฐ๊ฐ„ ์žฌ๊ฒ€์ฆ. +- โš  ์•ˆ์ • ๊ฒŒ์ดํŠธ 0๊ฑด โ†’ ์•ˆ์ • Top์€ **์ ์ˆ˜์ˆœ ํด๋ฐฑ** (์•ˆ์ • ๊ฒŒ์ดํŠธ 0๊ฑด โ†’ ํ•™์Šตํ’€ ์•ˆ์ •์ ์ˆ˜์ˆœ TopN (๋งˆ์ด๋„ˆ์Šค PnL ํฌํ•จ ยท ์ƒ๋Œ€๋น„๊ต)) + +## ์ด์ „ ์žฅ์—์„œ๋Š” +- ์‹ค๋งค ๋™๊ธฐ๊ฐ„ ์ฒญ์‚ฐ 13๊ฑด ยท ์Šน๋ฅ  31% ยท ํ•ฉ์‚ฐ PnL -34,618์› (๋ฐฑํ…Œ Optuna์™€ ์ˆซ์ž ๋‹ฌ๋ผ๋„ ์ •์ƒ โ€” ๊ณ ์ŠคํŠธยท์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑ ๊ฒฝ๋กœ ์ฐจ์ด). +- ์ด ๊ธฐ๊ฐ„ ๋ฐฑํ…Œ์—์„œ๋Š” **์œ ์˜๋ฏธํ•œ ํ†ต๊ณผ ์กฐํ•ฉ์ด ๊ฑฐ์˜ ์—†์—ˆ์Šต๋‹ˆ๋‹ค.** ์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑยท์†์ ˆยท์‹œ๊ฐ„์ฐฝ์„ ๋จผ์ € ์ ๊ฒ€ํ•˜์„ธ์š” (๋ŒํŒŒ 0๊ฑด์ด๋ฉด ํŠนํžˆ). + +## ์•ž์œผ๋กœ ์žฅ์—์„œ๋Š” +- **1~2์ผ Optuna best๋ฅผ ๋ฐ”๋กœ ์‹ค๋งค์— ๋„ฃ์ง€ ๋งˆ์„ธ์š”.** ๋‹ค์ผ(โ‰ฅ5๊ฑฐ๋ž˜์ผ) ์žฌ๊ฒ€์ฆยท์›น๋ฐฑํ…Œ 1ํšŒ ํ›„ ๊ฒ€ํ† . +- ์ ์šฉ ์‹œ์—๋Š” `results_gated` ํ›„๋ณด๋งŒ. ํƒ์ƒ‰์šฉ best(objective)์™€ ๋‹ค๋ฅผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. +- ์žฅ์ด ์ข์•„์ง€๊ฑฐ๋‚˜ ๋ณ€๋™์„ฑ์ด ์ปค์ง€๋ฉด: ์†์ ˆยทํŠธ๋ ˆ์ผยท์‹œ๊ฐ„์ฐฝ์ด ๋จผ์ € ๊นจ์ง‘๋‹ˆ๋‹ค. ์Šน๋ฅ  ์ž๋ž‘๋ณด๋‹ค **์†์ ˆ์ด ์‚ด์•„ ์žˆ๋Š”์ง€**๋ฅผ ๋ณด์„ธ์š”. +- ํ˜„์žฌ ์‚ฌํ›„ํ•ฉ๊ฒฉ 0๊ฑด โ†’ ํŒŒ๋ผ๋ฏธํ„ฐ ์œ ์ง€(ํ˜„ํ–‰ DB) + ์œ ๋‹ˆ๋ฒ„์Šค/๋ฐ์ดํ„ฐ ์ ๊ฒ€์ด ์šฐ์„ ์ž…๋‹ˆ๋‹ค. + +_์ƒ์„ฑ: 2026-09-05 01:29:51 (rule)_ + +## AI ์ฝ”๋ฉ˜ํŠธ (์ด์ „ ์žฅ / ์•ž์œผ๋กœ ์žฅ) [gemini] + +## ์ด์ „ ์žฅ์—์„œ๋Š” + +์ง€๋‚œ ํ•˜๋ฃจ ๋ฐฑํ…Œ์ŠคํŠธ๋Š” ์œ ์˜๋ฏธํ•œ ์ „๋žต ์กฐํ•ฉ์ด ์ „๋ฌดํ•˜๋ฉฐ, ๊ณผ์ ํ•ฉ ์œ„ํ—˜ 73%๋กœ '๋น„๊ถŒ์žฅ' ํŒ์ •์ž…๋‹ˆ๋‹ค. ์ด๋Š” ํ‘œ๋ณธ ๋ถ€์กฑ๊ณผ ๋‹จ์ผ ์žฅ ๊ณผ์ ํ•ฉ ์œ„ํ—˜์ด ์ตœ๋Œ€์น˜์ž„์„ ์˜๋ฏธํ•˜๋ฉฐ, ์‹ค๋งค ์ ์šฉ์€ ๋ถˆ๊ฐ€ํ•ฉ๋‹ˆ๋‹ค. ์‹ค์ œ ๊ฑฐ๋ž˜ ์†์‹ค๋„ ๋ฐœ์ƒํ–ˆ์œผ๋‹ˆ, ์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑยท๊ธฐ๊ฐ„ ๋“ฑ ๊ธฐ๋ณธ ์„ค์ •์„ ์ฆ‰์‹œ ์ ๊ฒ€ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. + +## ์•ž์œผ๋กœ ์žฅ์—์„œ๋Š” + +๋‹จ์ผ ์žฅ ๋ฐฑํ…Œ์ŠคํŠธ ๊ฒฐ๊ณผ๋Š” ๊ณผ์ ํ•ฉ ๋ฐ ํ‘œ๋ณธ ๋ถ€์กฑ ์œ„ํ—˜์ด ๋†’์•„ ์‹ค๋งค ์ ์šฉ์€ ์ ˆ๋Œ€ ๊ธˆ์ง€ํ•ฉ๋‹ˆ๋‹ค. ์‹ค๋งค์™€ ๋ฐฑํ…Œ์ŠคํŠธ ๊ฐ„ ๊ดด๋ฆฌ(๊ณ ์ŠคํŠธํผ์ง€ ๋“ฑ)๋„ ๋Š˜ ์ฃผ์˜ํ•˜์„ธ์š”. ๋ฐ˜๋“œ์‹œ ๋‹ค์ผ ์žฌ๊ฒ€์ฆ ํ›„ `results_gated` ์ „๋žต๋งŒ ์‹ ์ค‘ํžˆ ๊ณ ๋ คํ•˜์„ธ์š”. ํ˜„์žฌ ์‚ฌํ›„ํ•ฉ๊ฒฉ ์ „๋žต์ด ์—†์–ด ํ˜„ํ–‰ DB ์œ ์ง€ ๋ฐ ์œ ๋‹ˆ๋ฒ„์Šคยท๋ฐ์ดํ„ฐ ์žฌ์ ๊ฒ€์ด ์ตœ์šฐ์„ ์ž…๋‹ˆ๋‹ค. DB 1์ˆœ์œ„๋Š” `gated`์ด์ง€, `mode Top10 1์œ„`๊ฐ€ ์•„๋‹˜์„ ๋ช…์‹ฌํ•˜์„ธ์š”. diff --git a/kis_trader/backtest/results/optuna_breakout_tpe_20260905_013127.briefing.md b/kis_trader/backtest/results/optuna_breakout_tpe_20260905_013127.briefing.md new file mode 100644 index 0000000..8b9ed54 --- /dev/null +++ b/kis_trader/backtest/results/optuna_breakout_tpe_20260905_013127.briefing.md @@ -0,0 +1,49 @@ +# Optuna ๋ธŒ๋ฆฌํ•‘ โ€” ๋ŒํŒŒ (tpe) +๊ธฐ๊ฐ„: 2026-09-04 ~ 2026-09-04 (๊ฑฐ๋ž˜์ผโ‰ˆ1์ผ) ยท trials 200/200 +ํƒ์ƒ‰ ๊ฒŒ์ดํŠธ: WRโ‰ฅ0% PFโ‰ฅ0 ยท min_tradesโ‰ฅ2 | ํ›„๋ณด ๊ฒŒ์ดํŠธ: WRโ‰ฅ40% PFโ‰ฅ1 ยท min_tradesโ‰ฅ2 +- min_trades=2: **ํ•ฉ๊ฒฉ ์ธ์ • ์ตœ์†Œ ๊ฑฐ๋ž˜ ๊ฑด์ˆ˜**(ํ‘œ๋ณธ ๋ถ€์กฑยท์šฐ์—ฐ ์Šน๋ฅ  ๋ฐฉ์ง€). ์ด๋ณด๋‹ค ์ ์€ ์กฐํ•ฉ์€ ํ•™์Šต/ํ›„๋ณด ์ง‘๊ณ„์—์„œ ์ œ์™ธ๋ฉ๋‹ˆ๋‹ค. +ํ•™์Šต์šฉ ํ†ต๊ณผ 0๊ฑด ยท ์‚ฌํ›„ํ•ฉ๊ฒฉ(results_gated) 0๊ฑด + +## ๊ณผ์ ํ•ฉยท์ ์šฉ ๊ฐ€๋Šฅ๋„ (ํœด๋ฆฌ์Šคํ‹ฑ) +- **๊ณผ์ ํ•ฉ ์œ„ํ—˜ 73.0%** ยท **์ ์šฉ ๊ฐ€๋Šฅ๋„ 27.0%** ยท ํŒ์ •: **๋น„๊ถŒ์žฅ** โ€” ๊ณผ์ ํ•ฉยทํ‘œ๋ณธ๋ถ€์กฑ ์œ„ํ—˜ ๋†’์Œ โ€” ์‹ค๋งค DB ์ฆ‰์‹œ ์ ์šฉ ๋น„๊ถŒ์žฅ + - ํ‘œ๋ณธ ์žฅ์ผ: +40.0p โ€” ๊ฑฐ๋ž˜์ผโ‰ˆ1์ผ โ€” ๋‹จ์ผ ์žฅ ๊ณผ์ ํ•ฉ ์œ„ํ—˜ ์ตœ๋Œ€ + - ๊ฑฐ๋ž˜ ํ‘œ๋ณธ: +25.0p โ€” ํ†ต๊ณผ ํ›„๋ณด ์—†์Œ โ€” ์ ์šฉ ๋ถˆ๊ฐ€ + - ์Šน๋ฅ ยทPF ์ด์ƒ์น˜: +0.0p โ€” ์ด์ƒ์น˜ ์—†์Œ + - ๊ฒŒ์ดํŠธ ์ปค๋ฒ„: +8.0p โ€” ํ•™์Šตยทgated ๋ชจ๋‘ ๋น„์–ด ์žˆ์Œ + - PnL ๊ณ ์›: +0.0p โ€” ๊ณ ์› ํŒ์ • ์Šคํ‚ต +- _์ฐธ๊ณ : ๊ณผ์ ํ•ฉ%๋Š” ๊ต์ฐจ๊ฒ€์ฆ ์ ์ˆ˜๊ฐ€ ์•„๋‹ˆ๋ผ ํ‘œ๋ณธยท์ด์ƒ์น˜ยท๊ณ ์› ํœด๋ฆฌ์Šคํ‹ฑ์ž…๋‹ˆ๋‹ค. ์ ์šฉ ๊ฐ€๋Šฅ๋„%=100โˆ’๊ณผ์ ํ•ฉ์œ„ํ—˜%. DB ์ ์šฉ ๋ฒ„ํŠผ ํ™œ์„ฑ ์กฐ๊ฑด(gated PnL>0)๊ณผ๋Š” ๋ณ„๊ฐœ์ž…๋‹ˆ๋‹ค._ + +## ์ตœ์ข… ์„ ํƒ ํ›„๋ณด (๊ทœ์น™ ยท DB ์ ์šฉ ์ „ ํ™•์ธ) +- ์•„๋ž˜๋Š” **์—ญํ• ์ด ๋‹ค๋ฅธ** 4์ข… ํ›„๋ณด์ž…๋‹ˆ๋‹ค. mode Top10 1์œ„ โ‰  ์ต์ ˆ ๋Œ€ํ‘œ ยท **DB 1์ˆœ์œ„๋Š” ์‚ฌํ›„ํ•ฉ๊ฒฉ(gated)** ์ž…๋‹ˆ๋‹ค. +- mode pool: `positive` ยท scoring: `band_proximity_p25_p75` + +### ํ›„๋ณด 4์ข… +- **โ‘  ์‚ฌํ›„ํ•ฉ๊ฒฉ 1์œ„ (apply: gated)**: ์—†์Œ +- **โ‘ก ์•ˆ์ • 1์œ„ (apply: stable)**: ์—†์Œ +- **โ‘ข mode_combo (apply: mode)**: ์—†์Œ (๋ฏธ์‚ฐ์ถœยท๊ตฌ JSON) +- **โ‘ฃ mode Top10 1์œ„ (apply: consensus ยท ๋ฐด๋“œ ์ „ํ˜• trial)**: ์—†์Œ +- mode Top10 meta: pool 0๊ฑด ยท ์ถ• 0๊ฐœ + +### ์ถ”์ฒœ (์ž๋™ ยท confirm ํ•„์ˆ˜) +1. **์‚ฌํ›„ํ•ฉ๊ฒฉ 0๊ฑด โ†’ DB ์ ์šฉ ๋น„๊ถŒ์žฅ.** ํ˜„ํ–‰ DB ์œ ์ง€ + ์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑยท๊ธฐ๊ฐ„ ์žฌ๊ฒ€์ฆ. +- โš  ์•ˆ์ • ๊ฒŒ์ดํŠธ 0๊ฑด โ†’ ์•ˆ์ • Top์€ **์ ์ˆ˜์ˆœ ํด๋ฐฑ** (์•ˆ์ • ๊ฒŒ์ดํŠธ 0๊ฑด โ†’ ํ•™์Šตํ’€ ์•ˆ์ •์ ์ˆ˜์ˆœ TopN (๋งˆ์ด๋„ˆ์Šค PnL ํฌํ•จ ยท ์ƒ๋Œ€๋น„๊ต)) + +## ์ด์ „ ์žฅ์—์„œ๋Š” +- ์‹ค๋งค ๋™๊ธฐ๊ฐ„ ์ฒญ์‚ฐ 13๊ฑด ยท ์Šน๋ฅ  31% ยท ํ•ฉ์‚ฐ PnL -34,618์› (๋ฐฑํ…Œ Optuna์™€ ์ˆซ์ž ๋‹ฌ๋ผ๋„ ์ •์ƒ โ€” ๊ณ ์ŠคํŠธยท์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑ ๊ฒฝ๋กœ ์ฐจ์ด). +- ์ด ๊ธฐ๊ฐ„ ๋ฐฑํ…Œ์—์„œ๋Š” **์œ ์˜๋ฏธํ•œ ํ†ต๊ณผ ์กฐํ•ฉ์ด ๊ฑฐ์˜ ์—†์—ˆ์Šต๋‹ˆ๋‹ค.** ์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑยท์†์ ˆยท์‹œ๊ฐ„์ฐฝ์„ ๋จผ์ € ์ ๊ฒ€ํ•˜์„ธ์š” (๋ŒํŒŒ 0๊ฑด์ด๋ฉด ํŠนํžˆ). + +## ์•ž์œผ๋กœ ์žฅ์—์„œ๋Š” +- **1~2์ผ Optuna best๋ฅผ ๋ฐ”๋กœ ์‹ค๋งค์— ๋„ฃ์ง€ ๋งˆ์„ธ์š”.** ๋‹ค์ผ(โ‰ฅ5๊ฑฐ๋ž˜์ผ) ์žฌ๊ฒ€์ฆยท์›น๋ฐฑํ…Œ 1ํšŒ ํ›„ ๊ฒ€ํ† . +- ์ ์šฉ ์‹œ์—๋Š” `results_gated` ํ›„๋ณด๋งŒ. ํƒ์ƒ‰์šฉ best(objective)์™€ ๋‹ค๋ฅผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. +- ์žฅ์ด ์ข์•„์ง€๊ฑฐ๋‚˜ ๋ณ€๋™์„ฑ์ด ์ปค์ง€๋ฉด: ์†์ ˆยทํŠธ๋ ˆ์ผยท์‹œ๊ฐ„์ฐฝ์ด ๋จผ์ € ๊นจ์ง‘๋‹ˆ๋‹ค. ์Šน๋ฅ  ์ž๋ž‘๋ณด๋‹ค **์†์ ˆ์ด ์‚ด์•„ ์žˆ๋Š”์ง€**๋ฅผ ๋ณด์„ธ์š”. +- ํ˜„์žฌ ์‚ฌํ›„ํ•ฉ๊ฒฉ 0๊ฑด โ†’ ํŒŒ๋ผ๋ฏธํ„ฐ ์œ ์ง€(ํ˜„ํ–‰ DB) + ์œ ๋‹ˆ๋ฒ„์Šค/๋ฐ์ดํ„ฐ ์ ๊ฒ€์ด ์šฐ์„ ์ž…๋‹ˆ๋‹ค. + +_์ƒ์„ฑ: 2026-09-05 01:31:27 (rule)_ + +## AI ์ฝ”๋ฉ˜ํŠธ (์ด์ „ ์žฅ / ์•ž์œผ๋กœ ์žฅ) [gemini] + +### ์ด์ „ ์žฅ์—์„œ๋Š” +์‹ค๋งค์—์„œ๋Š” 13๊ฑด ๊ฑฐ๋ž˜์— ์Šน๋ฅ  31%, 3๋งŒ์›๋Œ€ ์†์‹ค์„ ๊ธฐ๋กํ–ˆ์Šต๋‹ˆ๋‹ค. ๋ฐฑํ…Œ์ŠคํŠธ์—์„œ๋„ ์œ ์˜๋ฏธํ•œ ํ†ต๊ณผ ์กฐํ•ฉ์ด ์ „๋ฌดํ•˜์—ฌ, 1์ผ์น˜ ์งง์€ ๊ธฐ๊ฐ„์˜ ๊ณผ์ ํ•ฉ ๋ฐ ํ‘œ๋ณธ ๋ถ€์กฑ ์œ„ํ—˜์ด ๋งค์šฐ ๋†’๊ฒŒ ๋‚˜ํƒ€๋‚ฌ์Šต๋‹ˆ๋‹ค. ๋ฐฑํ…Œ์ŠคํŠธ์™€ ์‹ค์ œ ๋งค๋งค ๊ฐ„ ๊ดด๋ฆฌ(๊ณ ์ŠคํŠธํผ์ง€ ๋“ฑ)๋„ ๋ถ„๋ช…ํ–ˆ์Šต๋‹ˆ๋‹ค. + +### ์•ž์œผ๋กœ ์žฅ์—์„œ๋Š” +์ด๋ฒˆ 1์ผ์น˜ Optuna ๊ฒฐ๊ณผ๋Š” ๊ณผ์ ํ•ฉ ์œ„ํ—˜ 73%, ์ ์šฉ ๊ฐ€๋Šฅ๋„ 27%๋กœ **์‹ค๋งค ์ ์šฉ์ด ๋น„๊ถŒ์žฅ๋ฉ๋‹ˆ๋‹ค.** ์‚ฌํ›„ํ•ฉ๊ฒฉ(gated)๋œ ์ „๋žต์ด ์ „๋ฌดํ•˜์—ฌ, ํ‘œ๋ณธ ๋ถ€์กฑ๊ณผ ๋‹จ์ผ ์žฅ์˜ ๊ณผ์ ํ•ฉ ์œ„ํ—˜์ด ๊ทน๋Œ€ํ™”๋˜์—ˆ์Œ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค. mode Top10 1์œ„ ๋“ฑ ์–ด๋–ค ํ›„๋ณด๋„ ์ต์ ˆ ๋Œ€ํ‘œ๋กœ ๋‹จ์ •ํ•  ์ˆ˜ ์—†์œผ๋ฉฐ, ํ™•์ • ์ˆ˜์ต์„ ์•ฝ์†ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ํ˜„ํ–‰ DB๋ฅผ ์œ ์ง€ํ•˜๋ฉฐ ์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑยท๊ธฐ๊ฐ„์„ ์žฌ๊ฒ€์ฆํ•˜๋Š” ๊ฒƒ์ด ์šฐ์„ ์ž…๋‹ˆ๋‹ค. diff --git a/kis_trader/backtest/results/optuna_momentum_fast_20260903_080735.briefing.md b/kis_trader/backtest/results/optuna_momentum_fast_20260903_080735.briefing.md new file mode 100644 index 0000000..56d01cc --- /dev/null +++ b/kis_trader/backtest/results/optuna_momentum_fast_20260903_080735.briefing.md @@ -0,0 +1,72 @@ +# Optuna ๋ธŒ๋ฆฌํ•‘ โ€” ๋ชจ๋ฉ˜ํ…€ (fast) +๊ธฐ๊ฐ„: 2026-08-27 ~ 2026-08-27 (๊ฑฐ๋ž˜์ผโ‰ˆ1์ผ) ยท trials 5/5 +ํƒ์ƒ‰ ๊ฒŒ์ดํŠธ: WRโ‰ฅ0% PFโ‰ฅ0 ยท min_tradesโ‰ฅ2 | ํ›„๋ณด ๊ฒŒ์ดํŠธ: WRโ‰ฅ40% PFโ‰ฅ1 ยท min_tradesโ‰ฅ2 +- min_trades=2: **ํ•ฉ๊ฒฉ ์ธ์ • ์ตœ์†Œ ๊ฑฐ๋ž˜ ๊ฑด์ˆ˜**(ํ‘œ๋ณธ ๋ถ€์กฑยท์šฐ์—ฐ ์Šน๋ฅ  ๋ฐฉ์ง€). ์ด๋ณด๋‹ค ์ ์€ ์กฐํ•ฉ์€ ํ•™์Šต/ํ›„๋ณด ์ง‘๊ณ„์—์„œ ์ œ์™ธ๋ฉ๋‹ˆ๋‹ค. +ํ•™์Šต์šฉ ํ†ต๊ณผ 5๊ฑด ยท ์‚ฌํ›„ํ•ฉ๊ฒฉ(results_gated) 0๊ฑด + +## ๊ณผ์ ํ•ฉยท์ ์šฉ ๊ฐ€๋Šฅ๋„ (ํœด๋ฆฌ์Šคํ‹ฑ) +- **๊ณผ์ ํ•ฉ ์œ„ํ—˜ 64.0%** ยท **์ ์šฉ ๊ฐ€๋Šฅ๋„ 36.0%** ยท ํŒ์ •: **์ฃผ์˜** โ€” ์ ์šฉ ๊ฐ€๋Šฅ๋„ ์ค‘๊ฐ„ โ€” ๋‹ค์ผ(โ‰ฅ5์ผ) ์žฌ๊ฒ€์ฆยท์›น๋ฐฑํ…Œ ํ›„ ์†Œ์•ก๋งŒ + - ํ‘œ๋ณธ ์žฅ์ผ: +40.0p โ€” ๊ฑฐ๋ž˜์ผโ‰ˆ1์ผ โ€” ๋‹จ์ผ ์žฅ ๊ณผ์ ํ•ฉ ์œ„ํ—˜ ์ตœ๋Œ€ + - ๊ฑฐ๋ž˜ ํ‘œ๋ณธ: +0.0p โ€” ์ƒ์œ„ ํ›„๋ณด ๊ฑฐ๋ž˜ 145๊ฑด โ€” ์ƒ๋Œ€์  ์–‘ํ˜ธ + - ์Šน๋ฅ ยทPF ์ด์ƒ์น˜: +0.0p โ€” ์ด์ƒ์น˜ ์—†์Œ + - ๊ฒŒ์ดํŠธ ์ปค๋ฒ„: +12.0p โ€” ์‚ฌํ›„ํ•ฉ๊ฒฉ 0๊ฑด (ํ•™์Šต 5) โ€” DB ์ ์šฉ ๋น„๊ถŒ์žฅ + - PnL ๊ณ ์›: +12.0p โ€” ๋™์ผ PnLโ‰ˆ0์›์ด ํ›„๋ณด 5/5 (100%) โ€” ํŒŒ๋ผ๋ฏธํ„ฐ ๋ฏผ๊ฐ๋„ ๋‚ฎ์Œ/๊ณ ์› +- ์ž„๊ณ„๊ฐ’ ๋ถ„ํฌ ํ‘œ๋ณธ: results(learning) ์ƒ์œ„ 5๊ฑด +| ํŒŒ๋ผ๋ฏธํ„ฐ | median | p25~p75 | mode(๋น„์œจ) | +|---|---:|---|---| +| `mom_rsi_min` | 55.0 | 49.0 ~ 55.0 | 49 (40%) | +| `mom_rsi_max` | 80.0 | 80.0 ~ 80.0 | 80 (80%) | +| `mom_vol_mult` | 2.0 | 1.0 ~ 2.0 | 1.0 (40%) | +| `e_min_chg_pct` | 0.5 | 0.0 ~ 0.5 | 0.5 (40%) | +| `tp_pct` | 5.0 | 3.0 ~ 15.0 | 15.0 (40%) | +| `sl_pct` | 5.0 | 4.0 ~ 5.0 | 5.0 (60%) | +| `mom_time_end_hm` | 1520.0 | 1520.0 ~ 1530.0 | 1530 (40%) | +| `mom_max_from_open_pct` | 40.0 | 25.0 ~ 56.0 | 56.0 (40%) | +| `min_margin` | 0.2 | 0.2 ~ 0.8 | 0.2 (60%) | +| `shoulder_min_high` | 0.9 | 0.8 ~ 3.0 | 3.0 (40%) | +| `shoulder_cut_pct` | 0.15 | 0.15 ~ 0.2 | 0.15 (60%) | +| `trail_pct` | 2.4 | 0.7 ~ 3.0 | 3.0 (40%) | +- _์ฐธ๊ณ : ๊ณผ์ ํ•ฉ%๋Š” ๊ต์ฐจ๊ฒ€์ฆ ์ ์ˆ˜๊ฐ€ ์•„๋‹ˆ๋ผ ํ‘œ๋ณธยท์ด์ƒ์น˜ยท๊ณ ์› ํœด๋ฆฌ์Šคํ‹ฑ์ž…๋‹ˆ๋‹ค. ์ ์šฉ ๊ฐ€๋Šฅ๋„%=100โˆ’๊ณผ์ ํ•ฉ์œ„ํ—˜%. DB ์ ์šฉ ๋ฒ„ํŠผ ํ™œ์„ฑ ์กฐ๊ฑด(gated PnL>0)๊ณผ๋Š” ๋ณ„๊ฐœ์ž…๋‹ˆ๋‹ค._ + +## ์ตœ์ข… ์„ ํƒ ํ›„๋ณด (๊ทœ์น™ ยท DB ์ ์šฉ ์ „ ํ™•์ธ) +- ์•„๋ž˜๋Š” **์—ญํ• ์ด ๋‹ค๋ฅธ** 4์ข… ํ›„๋ณด์ž…๋‹ˆ๋‹ค. mode Top10 1์œ„ โ‰  ์ต์ ˆ ๋Œ€ํ‘œ ยท **DB 1์ˆœ์œ„๋Š” ์‚ฌํ›„ํ•ฉ๊ฒฉ(gated)** ์ž…๋‹ˆ๋‹ค. +- mode pool: `positive` ยท scoring: `band_proximity_p25_p75` + +### ํ›„๋ณด 4์ข… +- **โ‘  ์‚ฌํ›„ํ•ฉ๊ฒฉ 1์œ„ (apply: gated)**: ์—†์Œ +- **โ‘ก ์•ˆ์ • 1์œ„ (apply: stable)** (trial #0): PnL 0์› ยท WR 0.0% ยท PF 9999.00 ยท ๊ฑฐ๋ž˜ 145๊ฑด ยท ์•ˆ์ •์ ์ˆ˜ 0 ยท ์ต์ ˆ15.0% ์†์ ˆ4.0% +- **โ‘ข mode_combo (apply: mode)** (trial ์—†์Œ(์กฐ๋ฆฝ)): PnL 0์› ยท WR 0.0% ยท PF 9999.00 ยท ๊ฑฐ๋ž˜ 191๊ฑด ยท ์•ˆ์ •์ ์ˆ˜ 0 ยท ์ต์ ˆ15.0% ์†์ ˆ5.0% ยท tp ์ตœ๋นˆ 15.0% (2/5) +- **โ‘ฃ mode Top10 1์œ„ (apply: consensus ยท ๋ฐด๋“œ ์ „ํ˜• trial)** (trial #3): PnL 0์› ยท WR 0.0% ยท PF 9999.00 ยท ๊ฑฐ๋ž˜ 154๊ฑด ยท ์•ˆ์ •์ ์ˆ˜ 0 ยท ๊ทผ์ ‘ 96.3% (17/18์ถ• ๋ฐด๋“œ์•ˆ) ยท ์ต์ ˆ3.0% ์†์ ˆ5.0% + +- mode pool tp_pct ๋ฐด๋“œ p25~p75: **3~15%** ยท Top10 1์œ„ tp=3% โ†’ ๋ฐด๋“œ **์•ˆ** +- mode Top10 meta: pool 5๊ฑด ยท ์ถ• 18๊ฐœ + +### ์ถ”์ฒœ (์ž๋™ ยท confirm ํ•„์ˆ˜) +1. **์‚ฌํ›„ํ•ฉ๊ฒฉ 0๊ฑด โ†’ DB ์ ์šฉ ๋น„๊ถŒ์žฅ.** ํ˜„ํ–‰ DB ์œ ์ง€ + ์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑยท๊ธฐ๊ฐ„ ์žฌ๊ฒ€์ฆ. +2. ์ฐธ๊ณ ๋งŒ: ํ•™์Šต 1์œ„๋Š” objective ์ตœ๋Œ€์ผ ๋ฟ ์‚ฌํ›„ ๊ฒŒ์ดํŠธ ๋ฏธํ†ต๊ณผ์ผ ์ˆ˜ ์žˆ์Œ. +2. **2์ฐจ narrowยท๋Œ€ํ‘œ ์ˆซ์ž โ†’ โ‘ข mode_combo** โ€” ์ถ•๋ณ„ ์ตœ๋นˆ ์กฐ๋ฆฝ ยท trial ๋ฒˆํ˜ธ ์—†์Œ ยท ์ต์ ˆ์€ pool ์ตœ๋นˆ๊ฐ’ ์ฐธ๊ณ . +3. **โ‘ฃ mode Top10 1์œ„** โ€” ์–‘์ˆ˜ pool ์ „ํ˜• trial(๋‹ค์ถ• ๋ฐด๋“œ ๊ทผ์ ‘). **์ต์ ˆ ํ•˜๋‚˜๋กœ ์“ฐ์ง€ ๋ง ๊ฒƒ** ยท ํ‘œ์—์„œ ใ€Œ๋ณด๊ธฐใ€โ†’ consensus apply. + +## ์ด์ „ ์žฅ์—์„œ๋Š” +- ์‹ค๋งค ๋™๊ธฐ๊ฐ„ ์ฒญ์‚ฐ 9๊ฑด ยท ์Šน๋ฅ  44% ยท ํ•ฉ์‚ฐ PnL -7,868์› (๋ฐฑํ…Œ Optuna์™€ ์ˆซ์ž ๋‹ฌ๋ผ๋„ ์ •์ƒ โ€” ๊ณ ์ŠคํŠธยท์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑ ๊ฒฝ๋กœ ์ฐจ์ด). +- ํ•™์Šต 1์œ„(์‚ฌํ›„๊ฒŒ์ดํŠธ ๋ฏธ๋‹ฌ ๊ฐ€๋Šฅ): trial #0 ยท ๊ฑฐ๋ž˜ 145๊ฑด ยท ์Šน๋ฅ  0.0% ยท PF 9999.00 ยท PnL 0์› +- ํ‘œ๋ณธ ์žฅ์ด 1์ผ๋ฟ์ด๋ผ, โ€˜์ด์ „ ์žฅ์— ์ž˜ ๋จนํžŒ ์ˆซ์žโ€™์ผ ๋ฟ **์ถ”์„ธ๊ฐ€ ๋ฐ”๋€Œ๋ฉด ๋ฐ”๋กœ ๊นจ์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.** +- ํ”Œ๋Ÿฌ์Šค/ํ•™์Šต ํ›„๋ณด๋Š” ์žˆ์œผ๋‚˜ ์Šน๋ฅ ยทPF ์‚ฌํ›„ ๊ธฐ์ค€์€ ๋ชป ๋„˜๊น€ โ†’ **๋‹น์žฅ DB ์ ์šฉ์€ ๋น„๊ถŒ์žฅ.** + +## ์•ž์œผ๋กœ ์žฅ์—์„œ๋Š” +- **1~2์ผ Optuna best๋ฅผ ๋ฐ”๋กœ ์‹ค๋งค์— ๋„ฃ์ง€ ๋งˆ์„ธ์š”.** ๋‹ค์ผ(โ‰ฅ5๊ฑฐ๋ž˜์ผ) ์žฌ๊ฒ€์ฆยท์›น๋ฐฑํ…Œ 1ํšŒ ํ›„ ๊ฒ€ํ† . +- ์ ์šฉ ์‹œ์—๋Š” `results_gated` ํ›„๋ณด๋งŒ. ํƒ์ƒ‰์šฉ best(objective)์™€ ๋‹ค๋ฅผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. +- ์žฅ์ด ์ข์•„์ง€๊ฑฐ๋‚˜ ๋ณ€๋™์„ฑ์ด ์ปค์ง€๋ฉด: ์†์ ˆยทํŠธ๋ ˆ์ผยท์‹œ๊ฐ„์ฐฝ์ด ๋จผ์ € ๊นจ์ง‘๋‹ˆ๋‹ค. ์Šน๋ฅ  ์ž๋ž‘๋ณด๋‹ค **์†์ ˆ์ด ์‚ด์•„ ์žˆ๋Š”์ง€**๋ฅผ ๋ณด์„ธ์š”. +- ํ˜„์žฌ ์‚ฌํ›„ํ•ฉ๊ฒฉ 0๊ฑด โ†’ ํŒŒ๋ผ๋ฏธํ„ฐ ์œ ์ง€(ํ˜„ํ–‰ DB) + ์œ ๋‹ˆ๋ฒ„์Šค/๋ฐ์ดํ„ฐ ์ ๊ฒ€์ด ์šฐ์„ ์ž…๋‹ˆ๋‹ค. + +_์ƒ์„ฑ: 2026-09-03 08:07:37 (rule)_ + +## AI ์ฝ”๋ฉ˜ํŠธ (์ด์ „ ์žฅ / ์•ž์œผ๋กœ ์žฅ) [gemini] + +## ์ด์ „ ์žฅ์—์„œ๋Š” + +์ด์ „ ์žฅ์—์„œ๋Š” 9๊ฑด์˜ ์‹ค๋งค ๊ฑฐ๋ž˜์—์„œ ์Šน๋ฅ  44%, PnL -7,868์›์„ ๊ธฐ๋กํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š” ๋ฐฑํ…Œ์ŠคํŠธ ๊ฒฐ๊ณผ์™€ ์‹ค๋งค ๊ฐ„์˜ ๊ดด๋ฆฌ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Œ์„ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค. Optuna ํƒ์ƒ‰์€ ๋‹จ 1์ผ ๋ฐฑํ…Œ์ŠคํŠธ๋กœ ์ง„ํ–‰๋˜์–ด ๊ณผ์ ํ•ฉ ์œ„ํ—˜์ด 64%๋กœ ๋งค์šฐ ๋†’์•˜๊ณ , 5๊ฐœ ํ•™์Šต ํ›„๋ณด ๋ชจ๋‘ PnL 0์›์œผ๋กœ ์‚ฌํ›„ ํ•ฉ๊ฒฉ ๊ธฐ์ค€์„ ํ†ต๊ณผํ•˜์ง€ ๋ชปํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š” ์ด์ „ ์žฅ์— ์šฐ์—ฐํžˆ ์ž˜ ๋งž์•˜์„ ๋ฟ, ํ‘œ๋ณธ ๋ถ€์กฑ๊ณผ ์šด์— ์˜ํ•œ ์Šน๋ฅ ์ผ ๊ฐ€๋Šฅ์„ฑ์ด ํฌ๋ฉฐ ์ถ”์„ธ ๋ณ€ํ™”์— ๋งค์šฐ ์ทจ์•ฝํ•จ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค. + +## ์•ž์œผ๋กœ ์žฅ์—์„œ๋Š” + +ํ˜„์žฌ ์‚ฌํ›„ํ•ฉ๊ฒฉ๋œ ์ „๋žต์ด ์ „๋ฌดํ•˜๋ฏ€๋กœ, DB ์ ์šฉ์€ ์ ˆ๋Œ€ ๊ธˆ์ง€๋ฉ๋‹ˆ๋‹ค. 1์ผ ๋ฐฑํ…Œ์ŠคํŠธ๋Š” ๊ณผ์ ํ•ฉ๊ณผ ํ‘œ๋ณธ ๋ถ€์กฑ ์œ„ํ—˜์ด ๋งค์šฐ ์ปค, ์‹ค๋งค์™€ ๋ฐฑํ…Œ์ŠคํŠธ ๊ฐ„ ๊ดด๋ฆฌ('๊ณ ์ŠคํŠธ ํผ์ง€' ๋“ฑ)๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. 'mode Top10 1์œ„'๋Š” ๋‹จ์ˆœ ํƒ์ƒ‰ ๊ฒฐ๊ณผ์ผ ๋ฟ ์‹ค์ œ ์ต์ ˆ์„ ๋ณด์žฅํ•˜์ง€ ์•Š์œผ๋ฉฐ, DB 1์ˆœ์œ„๋Š” ์‚ฌํ›„ํ•ฉ๊ฒฉ๋œ ์ „๋žต์ž„์„ ๋ช…์‹ฌํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๋ฐ˜๋“œ์‹œ ์ตœ์†Œ 5๊ฑฐ๋ž˜์ผ ์ด์ƒ์˜ ๋‹ค์ผ ์žฌ๊ฒ€์ฆ๊ณผ ์›น ๋ฐฑํ…Œ์ŠคํŠธ๋ฅผ ๋จผ์ € ์ˆ˜ํ–‰ํ•œ ํ›„ ์‹ ์ค‘ํžˆ ์ ‘๊ทผํ•˜์‹ญ์‹œ์˜ค. ์‹œ์žฅ ๋ณ€ํ™” ์‹œ ์Šน๋ฅ ๋ณด๋‹ค๋Š” ์†์ ˆ ๋ผ์ธ์ด ์ œ๋Œ€๋กœ ์ž‘๋™ํ•˜๋Š”์ง€ ํ™•์ธํ•˜๋Š” ๊ฒƒ์ด ํ•ต์‹ฌ์ž…๋‹ˆ๋‹ค. diff --git a/kis_trader/backtest/results/optuna_momentum_fast_20260903_080828.briefing.md b/kis_trader/backtest/results/optuna_momentum_fast_20260903_080828.briefing.md new file mode 100644 index 0000000..c74596b --- /dev/null +++ b/kis_trader/backtest/results/optuna_momentum_fast_20260903_080828.briefing.md @@ -0,0 +1,72 @@ +# Optuna ๋ธŒ๋ฆฌํ•‘ โ€” ๋ชจ๋ฉ˜ํ…€ (fast) +๊ธฐ๊ฐ„: 2026-08-27 ~ 2026-08-27 (๊ฑฐ๋ž˜์ผโ‰ˆ1์ผ) ยท trials 5/5 +ํƒ์ƒ‰ ๊ฒŒ์ดํŠธ: WRโ‰ฅ0% PFโ‰ฅ0 ยท min_tradesโ‰ฅ2 | ํ›„๋ณด ๊ฒŒ์ดํŠธ: WRโ‰ฅ40% PFโ‰ฅ1 ยท min_tradesโ‰ฅ2 +- min_trades=2: **ํ•ฉ๊ฒฉ ์ธ์ • ์ตœ์†Œ ๊ฑฐ๋ž˜ ๊ฑด์ˆ˜**(ํ‘œ๋ณธ ๋ถ€์กฑยท์šฐ์—ฐ ์Šน๋ฅ  ๋ฐฉ์ง€). ์ด๋ณด๋‹ค ์ ์€ ์กฐํ•ฉ์€ ํ•™์Šต/ํ›„๋ณด ์ง‘๊ณ„์—์„œ ์ œ์™ธ๋ฉ๋‹ˆ๋‹ค. +ํ•™์Šต์šฉ ํ†ต๊ณผ 5๊ฑด ยท ์‚ฌํ›„ํ•ฉ๊ฒฉ(results_gated) 0๊ฑด + +## ๊ณผ์ ํ•ฉยท์ ์šฉ ๊ฐ€๋Šฅ๋„ (ํœด๋ฆฌ์Šคํ‹ฑ) +- **๊ณผ์ ํ•ฉ ์œ„ํ—˜ 64.0%** ยท **์ ์šฉ ๊ฐ€๋Šฅ๋„ 36.0%** ยท ํŒ์ •: **์ฃผ์˜** โ€” ์ ์šฉ ๊ฐ€๋Šฅ๋„ ์ค‘๊ฐ„ โ€” ๋‹ค์ผ(โ‰ฅ5์ผ) ์žฌ๊ฒ€์ฆยท์›น๋ฐฑํ…Œ ํ›„ ์†Œ์•ก๋งŒ + - ํ‘œ๋ณธ ์žฅ์ผ: +40.0p โ€” ๊ฑฐ๋ž˜์ผโ‰ˆ1์ผ โ€” ๋‹จ์ผ ์žฅ ๊ณผ์ ํ•ฉ ์œ„ํ—˜ ์ตœ๋Œ€ + - ๊ฑฐ๋ž˜ ํ‘œ๋ณธ: +0.0p โ€” ์ƒ์œ„ ํ›„๋ณด ๊ฑฐ๋ž˜ 157๊ฑด โ€” ์ƒ๋Œ€์  ์–‘ํ˜ธ + - ์Šน๋ฅ ยทPF ์ด์ƒ์น˜: +0.0p โ€” ์ด์ƒ์น˜ ์—†์Œ + - ๊ฒŒ์ดํŠธ ์ปค๋ฒ„: +12.0p โ€” ์‚ฌํ›„ํ•ฉ๊ฒฉ 0๊ฑด (ํ•™์Šต 5) โ€” DB ์ ์šฉ ๋น„๊ถŒ์žฅ + - PnL ๊ณ ์›: +12.0p โ€” ๋™์ผ PnLโ‰ˆ0์›์ด ํ›„๋ณด 5/5 (100%) โ€” ํŒŒ๋ผ๋ฏธํ„ฐ ๋ฏผ๊ฐ๋„ ๋‚ฎ์Œ/๊ณ ์› +- ์ž„๊ณ„๊ฐ’ ๋ถ„ํฌ ํ‘œ๋ณธ: results(learning) ์ƒ์œ„ 5๊ฑด +| ํŒŒ๋ผ๋ฏธํ„ฐ | median | p25~p75 | mode(๋น„์œจ) | +|---|---:|---|---| +| `mom_rsi_min` | 58.0 | 52.0 ~ 58.0 | 58 (60%) | +| `mom_rsi_max` | 90.0 | 90.0 ~ 90.0 | 90 (80%) | +| `mom_vol_mult` | 1.0 | 1.0 ~ 2.0 | 1.0 (60%) | +| `e_min_chg_pct` | 0.2 | 0.0 ~ 0.5 | 0.5 (40%) | +| `tp_pct` | 3.0 | 3.0 ~ 3.0 | 3.0 (80%) | +| `sl_pct` | 5.0 | 5.0 ~ 5.0 | 5.0 (100%) | +| `mom_time_end_hm` | 1520.0 | 1520.0 ~ 1520.0 | 1520 (80%) | +| `mom_max_from_open_pct` | 40.0 | 40.0 ~ 40.0 | 40.0 (100%) | +| `min_margin` | 0.2 | 0.2 ~ 0.5 | 0.2 (60%) | +| `shoulder_min_high` | 0.9 | 0.9 ~ 0.9 | 0.9000000000000001 (80%) | +| `shoulder_cut_pct` | 0.2 | 0.15 ~ 0.2 | 0.2 (60%) | +| `trail_pct` | 0.7 | 0.0 ~ 0.7 | 0.0 (40%) | +- _์ฐธ๊ณ : ๊ณผ์ ํ•ฉ%๋Š” ๊ต์ฐจ๊ฒ€์ฆ ์ ์ˆ˜๊ฐ€ ์•„๋‹ˆ๋ผ ํ‘œ๋ณธยท์ด์ƒ์น˜ยท๊ณ ์› ํœด๋ฆฌ์Šคํ‹ฑ์ž…๋‹ˆ๋‹ค. ์ ์šฉ ๊ฐ€๋Šฅ๋„%=100โˆ’๊ณผ์ ํ•ฉ์œ„ํ—˜%. DB ์ ์šฉ ๋ฒ„ํŠผ ํ™œ์„ฑ ์กฐ๊ฑด(gated PnL>0)๊ณผ๋Š” ๋ณ„๊ฐœ์ž…๋‹ˆ๋‹ค._ + +## ์ตœ์ข… ์„ ํƒ ํ›„๋ณด (๊ทœ์น™ ยท DB ์ ์šฉ ์ „ ํ™•์ธ) +- ์•„๋ž˜๋Š” **์—ญํ• ์ด ๋‹ค๋ฅธ** 4์ข… ํ›„๋ณด์ž…๋‹ˆ๋‹ค. mode Top10 1์œ„ โ‰  ์ต์ ˆ ๋Œ€ํ‘œ ยท **DB 1์ˆœ์œ„๋Š” ์‚ฌํ›„ํ•ฉ๊ฒฉ(gated)** ์ž…๋‹ˆ๋‹ค. +- mode pool: `positive` ยท scoring: `band_proximity_p25_p75` + +### ํ›„๋ณด 4์ข… +- **โ‘  ์‚ฌํ›„ํ•ฉ๊ฒฉ 1์œ„ (apply: gated)**: ์—†์Œ +- **โ‘ก ์•ˆ์ • 1์œ„ (apply: stable)** (trial #0): PnL 0์› ยท WR 0.0% ยท PF 9999.00 ยท ๊ฑฐ๋ž˜ 157๊ฑด ยท ์•ˆ์ •์ ์ˆ˜ 0 ยท ์ต์ ˆ3.0% ์†์ ˆ5.0% +- **โ‘ข mode_combo (apply: mode)** (trial ์—†์Œ(์กฐ๋ฆฝ)): PnL 0์› ยท WR 0.0% ยท PF 9999.00 ยท ๊ฑฐ๋ž˜ 191๊ฑด ยท ์•ˆ์ •์ ์ˆ˜ 0 ยท ์ต์ ˆ3.0% ์†์ ˆ5.0% ยท tp ์ตœ๋นˆ 3.0% (4/5) +- **โ‘ฃ mode Top10 1์œ„ (apply: consensus ยท ๋ฐด๋“œ ์ „ํ˜• trial)** (trial #2): PnL 0์› ยท WR 0.0% ยท PF 9999.00 ยท ๊ฑฐ๋ž˜ 551๊ฑด ยท ์•ˆ์ •์ ์ˆ˜ 0 ยท ๊ทผ์ ‘ 99.5% (17/18์ถ• ๋ฐด๋“œ์•ˆ) ยท ์ต์ ˆ3.0% ์†์ ˆ5.0% + +- mode pool tp_pct ๋ฐด๋“œ p25~p75: **3~3%** ยท Top10 1์œ„ tp=3% โ†’ ๋ฐด๋“œ **์•ˆ** +- mode Top10 meta: pool 5๊ฑด ยท ์ถ• 18๊ฐœ + +### ์ถ”์ฒœ (์ž๋™ ยท confirm ํ•„์ˆ˜) +1. **์‚ฌํ›„ํ•ฉ๊ฒฉ 0๊ฑด โ†’ DB ์ ์šฉ ๋น„๊ถŒ์žฅ.** ํ˜„ํ–‰ DB ์œ ์ง€ + ์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑยท๊ธฐ๊ฐ„ ์žฌ๊ฒ€์ฆ. +2. ์ฐธ๊ณ ๋งŒ: ํ•™์Šต 1์œ„๋Š” objective ์ตœ๋Œ€์ผ ๋ฟ ์‚ฌํ›„ ๊ฒŒ์ดํŠธ ๋ฏธํ†ต๊ณผ์ผ ์ˆ˜ ์žˆ์Œ. +2. **2์ฐจ narrowยท๋Œ€ํ‘œ ์ˆซ์ž โ†’ โ‘ข mode_combo** โ€” ์ถ•๋ณ„ ์ตœ๋นˆ ์กฐ๋ฆฝ ยท trial ๋ฒˆํ˜ธ ์—†์Œ ยท ์ต์ ˆ์€ pool ์ตœ๋นˆ๊ฐ’ ์ฐธ๊ณ . +3. **โ‘ฃ mode Top10 1์œ„** โ€” ์–‘์ˆ˜ pool ์ „ํ˜• trial(๋‹ค์ถ• ๋ฐด๋“œ ๊ทผ์ ‘). **์ต์ ˆ ํ•˜๋‚˜๋กœ ์“ฐ์ง€ ๋ง ๊ฒƒ** ยท ํ‘œ์—์„œ ใ€Œ๋ณด๊ธฐใ€โ†’ consensus apply. + +## ์ด์ „ ์žฅ์—์„œ๋Š” +- ์‹ค๋งค ๋™๊ธฐ๊ฐ„ ์ฒญ์‚ฐ 9๊ฑด ยท ์Šน๋ฅ  44% ยท ํ•ฉ์‚ฐ PnL -7,868์› (๋ฐฑํ…Œ Optuna์™€ ์ˆซ์ž ๋‹ฌ๋ผ๋„ ์ •์ƒ โ€” ๊ณ ์ŠคํŠธยท์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑ ๊ฒฝ๋กœ ์ฐจ์ด). +- ํ•™์Šต 1์œ„(์‚ฌํ›„๊ฒŒ์ดํŠธ ๋ฏธ๋‹ฌ ๊ฐ€๋Šฅ): trial #0 ยท ๊ฑฐ๋ž˜ 157๊ฑด ยท ์Šน๋ฅ  0.0% ยท PF 9999.00 ยท PnL 0์› +- ํ‘œ๋ณธ ์žฅ์ด 1์ผ๋ฟ์ด๋ผ, โ€˜์ด์ „ ์žฅ์— ์ž˜ ๋จนํžŒ ์ˆซ์žโ€™์ผ ๋ฟ **์ถ”์„ธ๊ฐ€ ๋ฐ”๋€Œ๋ฉด ๋ฐ”๋กœ ๊นจ์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.** +- ํ”Œ๋Ÿฌ์Šค/ํ•™์Šต ํ›„๋ณด๋Š” ์žˆ์œผ๋‚˜ ์Šน๋ฅ ยทPF ์‚ฌํ›„ ๊ธฐ์ค€์€ ๋ชป ๋„˜๊น€ โ†’ **๋‹น์žฅ DB ์ ์šฉ์€ ๋น„๊ถŒ์žฅ.** + +## ์•ž์œผ๋กœ ์žฅ์—์„œ๋Š” +- **1~2์ผ Optuna best๋ฅผ ๋ฐ”๋กœ ์‹ค๋งค์— ๋„ฃ์ง€ ๋งˆ์„ธ์š”.** ๋‹ค์ผ(โ‰ฅ5๊ฑฐ๋ž˜์ผ) ์žฌ๊ฒ€์ฆยท์›น๋ฐฑํ…Œ 1ํšŒ ํ›„ ๊ฒ€ํ† . +- ์ ์šฉ ์‹œ์—๋Š” `results_gated` ํ›„๋ณด๋งŒ. ํƒ์ƒ‰์šฉ best(objective)์™€ ๋‹ค๋ฅผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. +- ์žฅ์ด ์ข์•„์ง€๊ฑฐ๋‚˜ ๋ณ€๋™์„ฑ์ด ์ปค์ง€๋ฉด: ์†์ ˆยทํŠธ๋ ˆ์ผยท์‹œ๊ฐ„์ฐฝ์ด ๋จผ์ € ๊นจ์ง‘๋‹ˆ๋‹ค. ์Šน๋ฅ  ์ž๋ž‘๋ณด๋‹ค **์†์ ˆ์ด ์‚ด์•„ ์žˆ๋Š”์ง€**๋ฅผ ๋ณด์„ธ์š”. +- ํ˜„์žฌ ์‚ฌํ›„ํ•ฉ๊ฒฉ 0๊ฑด โ†’ ํŒŒ๋ผ๋ฏธํ„ฐ ์œ ์ง€(ํ˜„ํ–‰ DB) + ์œ ๋‹ˆ๋ฒ„์Šค/๋ฐ์ดํ„ฐ ์ ๊ฒ€์ด ์šฐ์„ ์ž…๋‹ˆ๋‹ค. + +_์ƒ์„ฑ: 2026-09-03 08:08:29 (rule)_ + +## AI ์ฝ”๋ฉ˜ํŠธ (์ด์ „ ์žฅ / ์•ž์œผ๋กœ ์žฅ) [gemini] + +## ์ด์ „ ์žฅ์—์„œ๋Š” + +๋ชจ๋ฉ˜ํ…€(fast) ์ „๋žต์ด ๋‹จ ํ•˜๋ฃจ(1๊ฑฐ๋ž˜์ผ) ๋ฐ์ดํ„ฐ๋กœ ํ•™์Šต๋˜์–ด, ๊ณผ์ ํ•ฉ ์œ„ํ—˜์ด 64.0%๋กœ ๋งค์šฐ ๋†’์•˜์Šต๋‹ˆ๋‹ค. ๋ฐฑํ…Œ์ŠคํŠธ ์ƒ PnL์ด 0์›์œผ๋กœ ๋‚˜์™”์œผ๋‚˜, ์‹ค์ œ ๊ฑฐ๋ž˜์—์„œ๋Š” 9๊ฑด ์ค‘ 44% ์Šน๋ฅ ๋กœ -7,868์›์˜ ์†์‹ค์ด ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š” ๋ฐฑํ…Œ์ŠคํŠธ์™€ ์‹ค๋งค ๊ฐ„์˜ ๊ดด๋ฆฌ(๊ณ ์ŠคํŠธํผ์ง€ ๋“ฑ)๋ฅผ ๋ช…ํ™•ํžˆ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค. ํŠนํžˆ, **์‹ค๋งค ์ ์šฉ ๊ฐ€๋Šฅํ•œ ์‚ฌํ›„ํ•ฉ๊ฒฉ(gated)๋œ ์ „๋žต ์กฐํ•ฉ์ด ์ „ํ˜€ ์—†์—ˆ์œผ๋ฏ€๋กœ, ์ด์ „ ํ•™์Šต ๊ฒฐ๊ณผ๋Š” ๋‹จ์ˆœ ์ฐธ๊ณ ์šฉ์ผ ๋ฟ ์‹ค์ œ ์ˆ˜์ต์œผ๋กœ ์ง๊ฒฐ๋˜์ง€ ์•Š์Œ**์„ ๊ฒฝ๊ณ ํ•ฉ๋‹ˆ๋‹ค. + +## ์•ž์œผ๋กœ ์žฅ์—์„œ๋Š” + +๋‹จ์ผ ์žฅ์ผ ํ•™์Šต ๊ฒฐ๊ณผ๋Š” **์ ˆ๋Œ€ ์‹ค์ œ ๋งค๋งค์— ๋ฐ”๋กœ ์ ์šฉํ•ด์„œ๋Š” ์•ˆ ๋ฉ๋‹ˆ๋‹ค.** ์ตœ์†Œ 5๊ฑฐ๋ž˜์ผ ์ด์ƒ์˜ ๋‹ค์ผ ์žฌ๊ฒ€์ฆ๊ณผ ์›น๋ฐฑํ…Œ์ŠคํŠธ๋ฅผ ํ†ตํ•ด ์•ˆ์ •์„ฑ์„ ๋ฐ˜๋“œ์‹œ ํ™•์ธํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์‹ค๋งค ์ ์šฉ์€ `results_gated` ๊ธฐ์ค€์„ ํ†ต๊ณผํ•œ ์ „๋žต์œผ๋กœ๋งŒ ํ•œ์ •ํ•˜๋ฉฐ, **`mode Top10 1์œ„`๊ฐ€ ์ต์ ˆ ๋Œ€ํ‘œ๋ฅผ ์˜๋ฏธํ•˜์ง€ ์•Š์Œ**์„ ๋ช…์‹ฌํ•˜์‹ญ์‹œ์˜ค. ์‹œ์žฅ ๋ณ€ํ™” ์‹œ ๊ณผ์ ํ•ฉ๋œ ํŒŒ๋ผ๋ฏธํ„ฐ๋Š” ๋ฐ”๋กœ ๊นจ์งˆ ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ, ๋†’์€ ์Šน๋ฅ ๋ณด๋‹ค **์†์ ˆ ๋ผ์ธ์ด ์ œ๋Œ€๋กœ ์ž‘๋™ํ•˜๋Š”์ง€**๋ฅผ ์šฐ์„ ์ ์œผ๋กœ ์ ๊ฒ€ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ํ˜„์žฌ ์‚ฌํ›„ํ•ฉ๊ฒฉ 0๊ฑด์ด๋ฏ€๋กœ, ๊ธฐ์กด DB๋ฅผ ์œ ์ง€ํ•˜๋ฉฐ ์œ ๋‹ˆ๋ฒ„์Šค์™€ ๋ฐ์ดํ„ฐ๋ฅผ ์žฌ๊ฒ€ํ† ํ•˜๋Š” ๊ฒƒ์ด ์ตœ์„ ์ž…๋‹ˆ๋‹ค. diff --git a/kis_trader/backtest/results/optuna_momentum_tpe_20260903_194512.briefing.md b/kis_trader/backtest/results/optuna_momentum_tpe_20260903_194512.briefing.md new file mode 100644 index 0000000..e770aa3 --- /dev/null +++ b/kis_trader/backtest/results/optuna_momentum_tpe_20260903_194512.briefing.md @@ -0,0 +1,69 @@ +# Optuna ๋ธŒ๋ฆฌํ•‘ โ€” ๋ชจ๋ฉ˜ํ…€ (tpe) +๊ธฐ๊ฐ„: 2026-08-31 ~ 2026-09-03 (๊ฑฐ๋ž˜์ผโ‰ˆ4์ผ) ยท trials 200/200 +ํƒ์ƒ‰ ๊ฒŒ์ดํŠธ: WRโ‰ฅ0% PFโ‰ฅ0 ยท min_tradesโ‰ฅ8 | ํ›„๋ณด ๊ฒŒ์ดํŠธ: WRโ‰ฅ40% PFโ‰ฅ1 ยท min_tradesโ‰ฅ8 +- min_trades=8: **ํ•ฉ๊ฒฉ ์ธ์ • ์ตœ์†Œ ๊ฑฐ๋ž˜ ๊ฑด์ˆ˜**(ํ‘œ๋ณธ ๋ถ€์กฑยท์šฐ์—ฐ ์Šน๋ฅ  ๋ฐฉ์ง€). ์ด๋ณด๋‹ค ์ ์€ ์กฐํ•ฉ์€ ํ•™์Šต/ํ›„๋ณด ์ง‘๊ณ„์—์„œ ์ œ์™ธ๋ฉ๋‹ˆ๋‹ค. +ํ•™์Šต์šฉ ํ†ต๊ณผ 173๊ฑด ยท ์‚ฌํ›„ํ•ฉ๊ฒฉ(results_gated) 0๊ฑด + +## ๊ณผ์ ํ•ฉยท์ ์šฉ ๊ฐ€๋Šฅ๋„ (ํœด๋ฆฌ์Šคํ‹ฑ) +- **๊ณผ์ ํ•ฉ ์œ„ํ—˜ 40.0%** ยท **์ ์šฉ ๊ฐ€๋Šฅ๋„ 60.0%** ยท ํŒ์ •: **์ฃผ์˜** โ€” ์ ์šฉ ๊ฐ€๋Šฅ๋„ ์ค‘๊ฐ„ โ€” ๋‹ค์ผ(โ‰ฅ5์ผ) ์žฌ๊ฒ€์ฆยท์›น๋ฐฑํ…Œ ํ›„ ์†Œ์•ก๋งŒ + - ํ‘œ๋ณธ ์žฅ์ผ: +16.0p โ€” ๊ฑฐ๋ž˜์ผโ‰ˆ4์ผ โ€” ๋‹ค์ผ ์žฌ๊ฒ€์ฆ ๊ถŒ์žฅ(โ‰ฅ5์ผ) + - ๊ฑฐ๋ž˜ ํ‘œ๋ณธ: +0.0p โ€” ์ƒ์œ„ ํ›„๋ณด ๊ฑฐ๋ž˜ 989๊ฑด โ€” ์ƒ๋Œ€์  ์–‘ํ˜ธ + - ์Šน๋ฅ ยทPF ์ด์ƒ์น˜: +0.0p โ€” ์ด์ƒ์น˜ ์—†์Œ + - ๊ฒŒ์ดํŠธ ์ปค๋ฒ„: +12.0p โ€” ์‚ฌํ›„ํ•ฉ๊ฒฉ 0๊ฑด (ํ•™์Šต 173) โ€” DB ์ ์šฉ ๋น„๊ถŒ์žฅ + - PnL ๊ณ ์›: +12.0p โ€” ๋™์ผ PnLโ‰ˆ0์›์ด ํ›„๋ณด 173/173 (100%) โ€” ํŒŒ๋ผ๋ฏธํ„ฐ ๋ฏผ๊ฐ๋„ ๋‚ฎ์Œ/๊ณ ์› +- ์ž„๊ณ„๊ฐ’ ๋ถ„ํฌ ํ‘œ๋ณธ: results(learning) ์ƒ์œ„ 30๊ฑด +| ํŒŒ๋ผ๋ฏธํ„ฐ | median | p25~p75 | mode(๋น„์œจ) | +|---|---:|---|---| +| `use_ema_filter` | 1.0 | 0.0 ~ 1.0 | True (60%) | +| `ema_fast_period` | 11.5 | 9.0 ~ 15.75 | 10 (13%) | +| `ema_slow_period` | 36.0 | 28.0 ~ 46.25 | 28 (10%) | +| `mom_vol_mult` | 5.05 | 3.225 ~ 6.65 | 2.9 (7%) | +| `mom_vol_win` | 7.5 | 6.0 ~ 9.0 | 7 (20%) | +| `e_min_chg_pct` | 1.15 | 0.6 ~ 1.6 | 1.6 (10%) | +| `tp_pct` | 8.3 | 4.45 ~ 11.1 | 9.4 (7%) | +| `tp_max_pct` | 16.25 | 12.375 ~ 17.5 | 20.0 (13%) | +| `sl_pct` | 2.25 | 1.525 ~ 3.375 | 2.0 (13%) | +| `shoulder_min_high` | 1.4 | 0.825 ~ 2.6 | 0.3 (13%) | +| `shoulder_cut_pct` | 0.5 | 0.25 ~ 0.8 | 0.8 (30%) | +| `trail_pct` | 2.25 | 1.35 ~ 3.075 | 0.8 (10%) | +- _์ฐธ๊ณ : ๊ณผ์ ํ•ฉ%๋Š” ๊ต์ฐจ๊ฒ€์ฆ ์ ์ˆ˜๊ฐ€ ์•„๋‹ˆ๋ผ ํ‘œ๋ณธยท์ด์ƒ์น˜ยท๊ณ ์› ํœด๋ฆฌ์Šคํ‹ฑ์ž…๋‹ˆ๋‹ค. ์ ์šฉ ๊ฐ€๋Šฅ๋„%=100โˆ’๊ณผ์ ํ•ฉ์œ„ํ—˜%. DB ์ ์šฉ ๋ฒ„ํŠผ ํ™œ์„ฑ ์กฐ๊ฑด(gated PnL>0)๊ณผ๋Š” ๋ณ„๊ฐœ์ž…๋‹ˆ๋‹ค._ + +## ์ตœ์ข… ์„ ํƒ ํ›„๋ณด (๊ทœ์น™ ยท DB ์ ์šฉ ์ „ ํ™•์ธ) +- ์•„๋ž˜๋Š” **์—ญํ• ์ด ๋‹ค๋ฅธ** 4์ข… ํ›„๋ณด์ž…๋‹ˆ๋‹ค. mode Top10 1์œ„ โ‰  ์ต์ ˆ ๋Œ€ํ‘œ ยท **DB 1์ˆœ์œ„๋Š” ์‚ฌํ›„ํ•ฉ๊ฒฉ(gated)** ์ž…๋‹ˆ๋‹ค. +- mode pool: `positive` ยท scoring: `band_proximity_p25_p75` + +### ํ›„๋ณด 4์ข… +- **โ‘  ์‚ฌํ›„ํ•ฉ๊ฒฉ 1์œ„ (apply: gated)**: ์—†์Œ +- **โ‘ก ์•ˆ์ • 1์œ„ (apply: stable)** (trial #4): PnL 0์› ยท WR 0.0% ยท PF 9999.00 ยท ๊ฑฐ๋ž˜ 989๊ฑด ยท ์•ˆ์ •์ ์ˆ˜ 0 ยท ํ˜ธ๊ฐ€OFF ยท ์ต์ ˆ8.4% ์ƒํ•œ18.5% ์†์ ˆ3.1% ยท ํœฉ์˜ON sub45s lb120s dip0.80% tol0.05% +- **โ‘ข mode_combo (apply: mode)** (trial ์—†์Œ(์กฐ๋ฆฝ)): PnL 0์› ยท WR 0.0% ยท PF 9999.00 ยท ๊ฑฐ๋ž˜ 7805๊ฑด ยท ์•ˆ์ •์ ์ˆ˜ 0 ยท ํ˜ธ๊ฐ€ON spr2.0 r1.35 askร—1 ยท ์ต์ ˆ1.8% ์ƒํ•œ16.5% ์†์ ˆ3.3% ยท ํœฉ์˜ON sub15s lb120s dip0.40% tol0.20% ยท tp ์ตœ๋นˆ 1.8% (3/20) +- **โ‘ฃ mode Top10 1์œ„ (apply: consensus ยท ๋ฐด๋“œ ์ „ํ˜• trial)** (trial #182): PnL 0์› ยท WR 0.0% ยท PF 9999.00 ยท ๊ฑฐ๋ž˜ 3279๊ฑด ยท ์•ˆ์ •์ ์ˆ˜ 0 ยท ๊ทผ์ ‘ 97.2% (33/43์ถ• ๋ฐด๋“œ์•ˆ) ยท ํ˜ธ๊ฐ€ON spr2.7 r1.10 askร—64 ยท ์ต์ ˆ1.8% ์ƒํ•œ17.0% ์†์ ˆ0.6% ยท ํœฉ์˜ON sub15s lb120s dip0.60% tol0.20% + +- mode pool tp_pct ๋ฐด๋“œ p25~p75: **3.05~9.675%** ยท Top10 1์œ„ tp=1.8% โ†’ ๋ฐด๋“œ **๋ฐ–**(๋‹ค๋ฅธ ์ถ• ๋ณด์ •์œผ๋กœ ๊ทผ์ ‘% ๋†’์Œ) +- mode Top10 meta: pool 20๊ฑด ยท ์ถ• 43๊ฐœ + +### ์ถ”์ฒœ (์ž๋™ ยท confirm ํ•„์ˆ˜) +1. **์‚ฌํ›„ํ•ฉ๊ฒฉ 0๊ฑด โ†’ DB ์ ์šฉ ๋น„๊ถŒ์žฅ.** ํ˜„ํ–‰ DB ์œ ์ง€ + ์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑยท๊ธฐ๊ฐ„ ์žฌ๊ฒ€์ฆ. +2. ์ฐธ๊ณ ๋งŒ: ํ•™์Šต 1์œ„๋Š” objective ์ตœ๋Œ€์ผ ๋ฟ ์‚ฌํ›„ ๊ฒŒ์ดํŠธ ๋ฏธํ†ต๊ณผ์ผ ์ˆ˜ ์žˆ์Œ. +2. **2์ฐจ narrowยท๋Œ€ํ‘œ ์ˆซ์ž โ†’ โ‘ข mode_combo** โ€” ์ถ•๋ณ„ ์ตœ๋นˆ ์กฐ๋ฆฝ ยท trial ๋ฒˆํ˜ธ ์—†์Œ ยท ์ต์ ˆ์€ pool ์ตœ๋นˆ๊ฐ’ ์ฐธ๊ณ . +3. **โ‘ฃ mode Top10 1์œ„** โ€” ์–‘์ˆ˜ pool ์ „ํ˜• trial(๋‹ค์ถ• ๋ฐด๋“œ ๊ทผ์ ‘). **์ต์ ˆ ํ•˜๋‚˜๋กœ ์“ฐ์ง€ ๋ง ๊ฒƒ** ยท ํ‘œ์—์„œ ใ€Œ๋ณด๊ธฐใ€โ†’ consensus apply. + +## ์ด์ „ ์žฅ์—์„œ๋Š” +- ์‹ค๋งค ๋™๊ธฐ๊ฐ„ ์ฒญ์‚ฐ 50๊ฑด ยท ์Šน๋ฅ  42% ยท ํ•ฉ์‚ฐ PnL -87,112์› (๋ฐฑํ…Œ Optuna์™€ ์ˆซ์ž ๋‹ฌ๋ผ๋„ ์ •์ƒ โ€” ๊ณ ์ŠคํŠธยท์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑ ๊ฒฝ๋กœ ์ฐจ์ด). +- ํ•™์Šต 1์œ„(์‚ฌํ›„๊ฒŒ์ดํŠธ ๋ฏธ๋‹ฌ ๊ฐ€๋Šฅ): trial #4 ยท ๊ฑฐ๋ž˜ 989๊ฑด ยท ์Šน๋ฅ  0.0% ยท PF 9999.00 ยท PnL 0์› +- ํ”Œ๋Ÿฌ์Šค/ํ•™์Šต ํ›„๋ณด๋Š” ์žˆ์œผ๋‚˜ ์Šน๋ฅ ยทPF ์‚ฌํ›„ ๊ธฐ์ค€์€ ๋ชป ๋„˜๊น€ โ†’ **๋‹น์žฅ DB ์ ์šฉ์€ ๋น„๊ถŒ์žฅ.** + +## ์•ž์œผ๋กœ ์žฅ์—์„œ๋Š” +- **1~2์ผ Optuna best๋ฅผ ๋ฐ”๋กœ ์‹ค๋งค์— ๋„ฃ์ง€ ๋งˆ์„ธ์š”.** ๋‹ค์ผ(โ‰ฅ5๊ฑฐ๋ž˜์ผ) ์žฌ๊ฒ€์ฆยท์›น๋ฐฑํ…Œ 1ํšŒ ํ›„ ๊ฒ€ํ† . +- ์ ์šฉ ์‹œ์—๋Š” `results_gated` ํ›„๋ณด๋งŒ. ํƒ์ƒ‰์šฉ best(objective)์™€ ๋‹ค๋ฅผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. +- ์žฅ์ด ์ข์•„์ง€๊ฑฐ๋‚˜ ๋ณ€๋™์„ฑ์ด ์ปค์ง€๋ฉด: ์†์ ˆยทํŠธ๋ ˆ์ผยท์‹œ๊ฐ„์ฐฝ์ด ๋จผ์ € ๊นจ์ง‘๋‹ˆ๋‹ค. ์Šน๋ฅ  ์ž๋ž‘๋ณด๋‹ค **์†์ ˆ์ด ์‚ด์•„ ์žˆ๋Š”์ง€**๋ฅผ ๋ณด์„ธ์š”. +- ํ˜„์žฌ ์‚ฌํ›„ํ•ฉ๊ฒฉ 0๊ฑด โ†’ ํŒŒ๋ผ๋ฏธํ„ฐ ์œ ์ง€(ํ˜„ํ–‰ DB) + ์œ ๋‹ˆ๋ฒ„์Šค/๋ฐ์ดํ„ฐ ์ ๊ฒ€์ด ์šฐ์„ ์ž…๋‹ˆ๋‹ค. + +_์ƒ์„ฑ: 2026-09-03 19:45:24 (rule)_ + +## AI ์ฝ”๋ฉ˜ํŠธ (์ด์ „ ์žฅ / ์•ž์œผ๋กœ ์žฅ) [gemini] + +## ์ด์ „ ์žฅ์—์„œ๋Š” +์ด์ „ ์‹ค์ œ ๊ฑฐ๋ž˜์—์„œ๋Š” 50๊ฑด ์ฒญ์‚ฐ์—์„œ -87,112์› ์†์‹ค, ์Šน๋ฅ  42%๋ฅผ ๊ธฐ๋กํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š” ๋ฐฑํ…Œ์ŠคํŠธ ๊ฒฐ๊ณผ์™€๋Š” ๋‹ค๋ฅธ ์–‘์ƒ์ž…๋‹ˆ๋‹ค. ํ˜„์žฌ Optuna ํƒ์ƒ‰์€ 173๊ฑด์˜ ํ•™์Šต ํ›„๋ณด๋ฅผ ์ฐพ์•˜์œผ๋‚˜, ์‹ค์ œ ์ ์šฉ์„ ์œ„ํ•œ ์‚ฌํ›„ ํ•ฉ๊ฒฉ ๊ธฐ์ค€(์Šน๋ฅ  40%, PF 1.0)์„ ํ†ต๊ณผํ•œ ์กฐํ•ฉ์€ 0๊ฑด์ž…๋‹ˆ๋‹ค. ์ฆ‰, ์ง€๋‚œ 4์ผ๊ฐ„ ์œ ์˜๋ฏธํ•œ ์ˆ˜์ต์„ ๋‚ด๋ฉฐ ๊ฒ€์ฆ๋œ ํŒŒ๋ผ๋ฏธํ„ฐ๋Š” ์—†์—ˆ์Šต๋‹ˆ๋‹ค. + +## ์•ž์œผ๋กœ ์žฅ์—์„œ๋Š” +์ด ๊ฒฐ๊ณผ๋Š” ๋งค์šฐ ์งง์€ 4์ผ ๋ฐฑํ…Œ์ŠคํŠธ ๊ธฐ๊ฐ„์œผ๋กœ ๊ณผ์ ํ•ฉยทํ‘œ๋ณธ ๋ถ€์กฑ ์œ„ํ—˜์ด ๋งค์šฐ ๋†’์Šต๋‹ˆ๋‹ค. ๋ฐฑํ…Œ์ŠคํŠธ์™€ ์‹ค๋งค ๊ฐ„์˜ ๊ดด๋ฆฌ(Ghost/Slippage ๋“ฑ)๋„ ๋ถ„๋ช…ํžˆ ๊ฒฝ๊ณ ํ•ฉ๋‹ˆ๋‹ค. Optuna Top10 1์œ„๋„ ์ต์ ˆ ๋Œ€ํ‘œ๊ฐ€ ์•„๋‹ˆ๋ฉฐ, ์‚ฌํ›„ํ•ฉ๊ฒฉ(Gated)๋œ ์กฐํ•ฉ๋งŒ ์‹ค๋งค ์ ์šฉ์„ ๊ณ ๋ คํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ํ˜„์žฌ 0๊ฑด์ด๋ฏ€๋กœ ๊ธฐ์กด ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ์œ ์ง€ํ•˜๋ฉฐ ๋‹ค์ผ(โ‰ฅ5์ผ) ์žฌ๊ฒ€์ฆ์ด ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค. ํŠน์ • ์ข…๋ชฉ ๋งค์ˆ˜ ๋ฐ ํ™•์ • ์ˆ˜์ต์€ ์ ˆ๋Œ€ ์•ฝ์†ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. diff --git a/kis_trader/backtest/results/optuna_momentum_tpe_20260903_200417.briefing.md b/kis_trader/backtest/results/optuna_momentum_tpe_20260903_200417.briefing.md new file mode 100644 index 0000000..9fc1d6c --- /dev/null +++ b/kis_trader/backtest/results/optuna_momentum_tpe_20260903_200417.briefing.md @@ -0,0 +1,69 @@ +# Optuna ๋ธŒ๋ฆฌํ•‘ โ€” ๋ชจ๋ฉ˜ํ…€ (tpe) +๊ธฐ๊ฐ„: 2026-08-31 ~ 2026-09-03 (๊ฑฐ๋ž˜์ผโ‰ˆ4์ผ) ยท trials 200/200 +ํƒ์ƒ‰ ๊ฒŒ์ดํŠธ: WRโ‰ฅ0% PFโ‰ฅ0 ยท min_tradesโ‰ฅ8 | ํ›„๋ณด ๊ฒŒ์ดํŠธ: WRโ‰ฅ40% PFโ‰ฅ1 ยท min_tradesโ‰ฅ8 +- min_trades=8: **ํ•ฉ๊ฒฉ ์ธ์ • ์ตœ์†Œ ๊ฑฐ๋ž˜ ๊ฑด์ˆ˜**(ํ‘œ๋ณธ ๋ถ€์กฑยท์šฐ์—ฐ ์Šน๋ฅ  ๋ฐฉ์ง€). ์ด๋ณด๋‹ค ์ ์€ ์กฐํ•ฉ์€ ํ•™์Šต/ํ›„๋ณด ์ง‘๊ณ„์—์„œ ์ œ์™ธ๋ฉ๋‹ˆ๋‹ค. +ํ•™์Šต์šฉ ํ†ต๊ณผ 171๊ฑด ยท ์‚ฌํ›„ํ•ฉ๊ฒฉ(results_gated) 0๊ฑด + +## ๊ณผ์ ํ•ฉยท์ ์šฉ ๊ฐ€๋Šฅ๋„ (ํœด๋ฆฌ์Šคํ‹ฑ) +- **๊ณผ์ ํ•ฉ ์œ„ํ—˜ 40.0%** ยท **์ ์šฉ ๊ฐ€๋Šฅ๋„ 60.0%** ยท ํŒ์ •: **์ฃผ์˜** โ€” ์ ์šฉ ๊ฐ€๋Šฅ๋„ ์ค‘๊ฐ„ โ€” ๋‹ค์ผ(โ‰ฅ5์ผ) ์žฌ๊ฒ€์ฆยท์›น๋ฐฑํ…Œ ํ›„ ์†Œ์•ก๋งŒ + - ํ‘œ๋ณธ ์žฅ์ผ: +16.0p โ€” ๊ฑฐ๋ž˜์ผโ‰ˆ4์ผ โ€” ๋‹ค์ผ ์žฌ๊ฒ€์ฆ ๊ถŒ์žฅ(โ‰ฅ5์ผ) + - ๊ฑฐ๋ž˜ ํ‘œ๋ณธ: +0.0p โ€” ์ƒ์œ„ ํ›„๋ณด ๊ฑฐ๋ž˜ 778๊ฑด โ€” ์ƒ๋Œ€์  ์–‘ํ˜ธ + - ์Šน๋ฅ ยทPF ์ด์ƒ์น˜: +0.0p โ€” ์ด์ƒ์น˜ ์—†์Œ + - ๊ฒŒ์ดํŠธ ์ปค๋ฒ„: +12.0p โ€” ์‚ฌํ›„ํ•ฉ๊ฒฉ 0๊ฑด (ํ•™์Šต 171) โ€” DB ์ ์šฉ ๋น„๊ถŒ์žฅ + - PnL ๊ณ ์›: +12.0p โ€” ๋™์ผ PnLโ‰ˆ0์›์ด ํ›„๋ณด 171/171 (100%) โ€” ํŒŒ๋ผ๋ฏธํ„ฐ ๋ฏผ๊ฐ๋„ ๋‚ฎ์Œ/๊ณ ์› +- ์ž„๊ณ„๊ฐ’ ๋ถ„ํฌ ํ‘œ๋ณธ: results(learning) ์ƒ์œ„ 30๊ฑด +| ํŒŒ๋ผ๋ฏธํ„ฐ | median | p25~p75 | mode(๋น„์œจ) | +|---|---:|---|---| +| `use_ema_filter` | 0.0 | 0.0 ~ 1.0 | False (70%) | +| `ema_fast_period` | 10.0 | 7.0 ~ 11.75 | 10 (23%) | +| `ema_slow_period` | 40.0 | 35.0 ~ 49.0 | 40 (13%) | +| `mom_vol_mult` | 3.35 | 2.45 ~ 5.0 | 2.9 (10%) | +| `mom_vol_win` | 9.0 | 7.0 ~ 10.0 | 10 (30%) | +| `e_min_chg_pct` | 2.4 | 1.625 ~ 2.7 | 3.0 (20%) | +| `tp_pct` | 5.55 | 3.95 ~ 7.35 | 4.8 (10%) | +| `tp_max_pct` | 11.75 | 8.125 ~ 15.875 | 18.0 (7%) | +| `sl_pct` | 4.8 | 2.35 ~ 7.475 | 8.0 (17%) | +| `shoulder_min_high` | 2.35 | 1.55 ~ 2.9 | 2.9 (10%) | +| `shoulder_cut_pct` | 0.35 | 0.2125 ~ 0.5875 | 0.35 (13%) | +| `trail_pct` | 2.25 | 1.125 ~ 2.975 | 0.0 (10%) | +- _์ฐธ๊ณ : ๊ณผ์ ํ•ฉ%๋Š” ๊ต์ฐจ๊ฒ€์ฆ ์ ์ˆ˜๊ฐ€ ์•„๋‹ˆ๋ผ ํ‘œ๋ณธยท์ด์ƒ์น˜ยท๊ณ ์› ํœด๋ฆฌ์Šคํ‹ฑ์ž…๋‹ˆ๋‹ค. ์ ์šฉ ๊ฐ€๋Šฅ๋„%=100โˆ’๊ณผ์ ํ•ฉ์œ„ํ—˜%. DB ์ ์šฉ ๋ฒ„ํŠผ ํ™œ์„ฑ ์กฐ๊ฑด(gated PnL>0)๊ณผ๋Š” ๋ณ„๊ฐœ์ž…๋‹ˆ๋‹ค._ + +## ์ตœ์ข… ์„ ํƒ ํ›„๋ณด (๊ทœ์น™ ยท DB ์ ์šฉ ์ „ ํ™•์ธ) +- ์•„๋ž˜๋Š” **์—ญํ• ์ด ๋‹ค๋ฅธ** 4์ข… ํ›„๋ณด์ž…๋‹ˆ๋‹ค. mode Top10 1์œ„ โ‰  ์ต์ ˆ ๋Œ€ํ‘œ ยท **DB 1์ˆœ์œ„๋Š” ์‚ฌํ›„ํ•ฉ๊ฒฉ(gated)** ์ž…๋‹ˆ๋‹ค. +- mode pool: `positive` ยท scoring: `band_proximity_p25_p75` + +### ํ›„๋ณด 4์ข… +- **โ‘  ์‚ฌํ›„ํ•ฉ๊ฒฉ 1์œ„ (apply: gated)**: ์—†์Œ +- **โ‘ก ์•ˆ์ • 1์œ„ (apply: stable)** (trial #1): PnL 0์› ยท WR 0.0% ยท PF 9999.00 ยท ๊ฑฐ๋ž˜ 778๊ฑด ยท ์•ˆ์ •์ ์ˆ˜ 0 ยท ํ˜ธ๊ฐ€ON spr2.9 r1.40 askร—15 ยท ์ต์ ˆ8.9% ์ƒํ•œ18.0% ์†์ ˆ7.9% ยท ํœฉ์˜ON sub45s lb120s dip1.00% tol0.05% +- **โ‘ข mode_combo (apply: mode)** (trial ์—†์Œ(์กฐ๋ฆฝ)): PnL 0์› ยท WR 0.0% ยท PF 9999.00 ยท ๊ฑฐ๋ž˜ 2578๊ฑด ยท ์•ˆ์ •์ ์ˆ˜ 0 ยท ํ˜ธ๊ฐ€OFF ยท ์ต์ ˆ4.2% ์ƒํ•œ8.5% ์†์ ˆ8.0% ยท ํœฉ์˜ON sub45s lb180s dip1.00% tol0.05% ยท tp ์ตœ๋นˆ 4.2% (2/20) +- **โ‘ฃ mode Top10 1์œ„ (apply: consensus ยท ๋ฐด๋“œ ์ „ํ˜• trial)** (trial #4): PnL 0์› ยท WR 0.0% ยท PF 9999.00 ยท ๊ฑฐ๋ž˜ 2081๊ฑด ยท ์•ˆ์ •์ ์ˆ˜ 0 ยท ๊ทผ์ ‘ 98.0% (34/43์ถ• ๋ฐด๋“œ์•ˆ) ยท ํ˜ธ๊ฐ€OFF ยท ์ต์ ˆ4.8% ์ƒํ•œ8.5% ์†์ ˆ2.2% ยท ํœฉ์˜OFF + +- mode pool tp_pct ๋ฐด๋“œ p25~p75: **4.2~6.85%** ยท Top10 1์œ„ tp=4.8% โ†’ ๋ฐด๋“œ **์•ˆ** +- mode Top10 meta: pool 20๊ฑด ยท ์ถ• 43๊ฐœ + +### ์ถ”์ฒœ (์ž๋™ ยท confirm ํ•„์ˆ˜) +1. **์‚ฌํ›„ํ•ฉ๊ฒฉ 0๊ฑด โ†’ DB ์ ์šฉ ๋น„๊ถŒ์žฅ.** ํ˜„ํ–‰ DB ์œ ์ง€ + ์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑยท๊ธฐ๊ฐ„ ์žฌ๊ฒ€์ฆ. +2. ์ฐธ๊ณ ๋งŒ: ํ•™์Šต 1์œ„๋Š” objective ์ตœ๋Œ€์ผ ๋ฟ ์‚ฌํ›„ ๊ฒŒ์ดํŠธ ๋ฏธํ†ต๊ณผ์ผ ์ˆ˜ ์žˆ์Œ. +2. **2์ฐจ narrowยท๋Œ€ํ‘œ ์ˆซ์ž โ†’ โ‘ข mode_combo** โ€” ์ถ•๋ณ„ ์ตœ๋นˆ ์กฐ๋ฆฝ ยท trial ๋ฒˆํ˜ธ ์—†์Œ ยท ์ต์ ˆ์€ pool ์ตœ๋นˆ๊ฐ’ ์ฐธ๊ณ . +3. **โ‘ฃ mode Top10 1์œ„** โ€” ์–‘์ˆ˜ pool ์ „ํ˜• trial(๋‹ค์ถ• ๋ฐด๋“œ ๊ทผ์ ‘). **์ต์ ˆ ํ•˜๋‚˜๋กœ ์“ฐ์ง€ ๋ง ๊ฒƒ** ยท ํ‘œ์—์„œ ใ€Œ๋ณด๊ธฐใ€โ†’ consensus apply. + +## ์ด์ „ ์žฅ์—์„œ๋Š” +- ์‹ค๋งค ๋™๊ธฐ๊ฐ„ ์ฒญ์‚ฐ 50๊ฑด ยท ์Šน๋ฅ  42% ยท ํ•ฉ์‚ฐ PnL -87,112์› (๋ฐฑํ…Œ Optuna์™€ ์ˆซ์ž ๋‹ฌ๋ผ๋„ ์ •์ƒ โ€” ๊ณ ์ŠคํŠธยท์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑ ๊ฒฝ๋กœ ์ฐจ์ด). +- ํ•™์Šต 1์œ„(์‚ฌํ›„๊ฒŒ์ดํŠธ ๋ฏธ๋‹ฌ ๊ฐ€๋Šฅ): trial #1 ยท ๊ฑฐ๋ž˜ 778๊ฑด ยท ์Šน๋ฅ  0.0% ยท PF 9999.00 ยท PnL 0์› +- ํ”Œ๋Ÿฌ์Šค/ํ•™์Šต ํ›„๋ณด๋Š” ์žˆ์œผ๋‚˜ ์Šน๋ฅ ยทPF ์‚ฌํ›„ ๊ธฐ์ค€์€ ๋ชป ๋„˜๊น€ โ†’ **๋‹น์žฅ DB ์ ์šฉ์€ ๋น„๊ถŒ์žฅ.** + +## ์•ž์œผ๋กœ ์žฅ์—์„œ๋Š” +- **1~2์ผ Optuna best๋ฅผ ๋ฐ”๋กœ ์‹ค๋งค์— ๋„ฃ์ง€ ๋งˆ์„ธ์š”.** ๋‹ค์ผ(โ‰ฅ5๊ฑฐ๋ž˜์ผ) ์žฌ๊ฒ€์ฆยท์›น๋ฐฑํ…Œ 1ํšŒ ํ›„ ๊ฒ€ํ† . +- ์ ์šฉ ์‹œ์—๋Š” `results_gated` ํ›„๋ณด๋งŒ. ํƒ์ƒ‰์šฉ best(objective)์™€ ๋‹ค๋ฅผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. +- ์žฅ์ด ์ข์•„์ง€๊ฑฐ๋‚˜ ๋ณ€๋™์„ฑ์ด ์ปค์ง€๋ฉด: ์†์ ˆยทํŠธ๋ ˆ์ผยท์‹œ๊ฐ„์ฐฝ์ด ๋จผ์ € ๊นจ์ง‘๋‹ˆ๋‹ค. ์Šน๋ฅ  ์ž๋ž‘๋ณด๋‹ค **์†์ ˆ์ด ์‚ด์•„ ์žˆ๋Š”์ง€**๋ฅผ ๋ณด์„ธ์š”. +- ํ˜„์žฌ ์‚ฌํ›„ํ•ฉ๊ฒฉ 0๊ฑด โ†’ ํŒŒ๋ผ๋ฏธํ„ฐ ์œ ์ง€(ํ˜„ํ–‰ DB) + ์œ ๋‹ˆ๋ฒ„์Šค/๋ฐ์ดํ„ฐ ์ ๊ฒ€์ด ์šฐ์„ ์ž…๋‹ˆ๋‹ค. + +_์ƒ์„ฑ: 2026-09-03 20:04:26 (rule)_ + +## AI ์ฝ”๋ฉ˜ํŠธ (์ด์ „ ์žฅ / ์•ž์œผ๋กœ ์žฅ) [gemini] + +## ์ด์ „ ์žฅ์—์„œ๋Š” +์‹ค์ œ ๋งค๋งค์—์„œ 50๊ฑด ๊ฑฐ๋ž˜๋กœ -87,112์› ์†์‹ค(์Šน๋ฅ  42%)์„ ๊ธฐ๋กํ–ˆ์Šต๋‹ˆ๋‹ค. Optuna ๋ฐฑํ…Œ์ŠคํŠธ๋Š” 4์ผ๊ฐ„ ์ง„ํ–‰๋˜์—ˆ์œผ๋‚˜, ํ•™์Šต๋œ ๋ชจ๋“  ์กฐํ•ฉ์ด PnL 0์›, ์Šน๋ฅ  0%๋กœ ๋‚˜ํƒ€๋‚ฌ์Šต๋‹ˆ๋‹ค. ํŠนํžˆ, ์‹ค๋งค ์ ์šฉ ๊ธฐ์ค€์„ ํ†ต๊ณผํ•œ '์‚ฌํ›„ํ•ฉ๊ฒฉ' ์กฐํ•ฉ์€ ๋‹จ ํ•˜๋‚˜๋„ ์—†์—ˆ์Šต๋‹ˆ๋‹ค. + +## ์•ž์œผ๋กœ ์žฅ์—์„œ๋Š” +4์ผ๊ฐ„์˜ ์งง์€ ๋ฐฑํ…Œ์ŠคํŠธ๋Š” ๊ณผ์ ํ•ฉ ๋ฐ ํ‘œ๋ณธ ๋ถ€์กฑ ์œ„ํ—˜์ด ํฝ๋‹ˆ๋‹ค. ๋ชจ๋“  ํ›„๋ณด PnL์ด 0์›์ด๋ฏ€๋กœ ์‹ค๋งค ์ ์šฉ์€ ์ ˆ๋Œ€ ๊ธˆ์ง€ํ•˜๋ฉฐ, ๋ฐฑํ…Œ์ŠคํŠธ์™€ ์‹ค๋งค ๊ดด๋ฆฌ(๊ณ ์ŠคํŠธ ํผ์ง€)๋ฅผ ํ•ญ์ƒ ๊ฒฝ๊ณ ํ•ฉ๋‹ˆ๋‹ค. Optuna 'mode Top10 1์œ„'๋ฅผ ์ต์ ˆ ๋Œ€ํ‘œ๋กœ ๋‹จ์ •ํ•˜์ง€ ๋งˆ์„ธ์š”. DB 1์ˆœ์œ„๋Š” ์‚ฌํ›„ ํ•ฉ๊ฒฉ์กฐํ•ฉ์ด๋ฉฐ, ํ˜„์žฌ๋Š” 0๊ฑด์ž…๋‹ˆ๋‹ค. ํŠน์ • ์ข…๋ชฉ ์ถ”์ฒœ์ด๋‚˜ ํ™•์ • ์ˆ˜์ต์€ ๋ถˆ๊ฐ€ํ•ฉ๋‹ˆ๋‹ค. ์ตœ์†Œ 5๊ฑฐ๋ž˜์ผ ์ด์ƒ ์žฌ๊ฒ€์ฆ๊ณผ ๋ฐ์ดํ„ฐ ์ ๊ฒ€ ํ›„ ๊ธฐ์กด ํŒŒ๋ผ๋ฏธํ„ฐ ์œ ์ง€ํ•˜๋Š” ๊ฒƒ์ด ํ˜„๋ช…ํ•ฉ๋‹ˆ๋‹ค. diff --git a/kis_trader/backtest/results/optuna_scalp_tpe_20260905_014714.briefing.md b/kis_trader/backtest/results/optuna_scalp_tpe_20260905_014714.briefing.md new file mode 100644 index 0000000..7ec3fa6 --- /dev/null +++ b/kis_trader/backtest/results/optuna_scalp_tpe_20260905_014714.briefing.md @@ -0,0 +1,73 @@ +# Optuna ๋ธŒ๋ฆฌํ•‘ โ€” ์Šค์บ˜ํ•‘ (tpe) +๊ธฐ๊ฐ„: 2026-09-04 ~ 2026-09-04 (๊ฑฐ๋ž˜์ผโ‰ˆ1์ผ) ยท trials 200/200 +ํƒ์ƒ‰ ๊ฒŒ์ดํŠธ: WRโ‰ฅ0% PFโ‰ฅ0 ยท min_tradesโ‰ฅ2 | ํ›„๋ณด ๊ฒŒ์ดํŠธ: WRโ‰ฅ40% PFโ‰ฅ1 ยท min_tradesโ‰ฅ2 +- min_trades=2: **ํ•ฉ๊ฒฉ ์ธ์ • ์ตœ์†Œ ๊ฑฐ๋ž˜ ๊ฑด์ˆ˜**(ํ‘œ๋ณธ ๋ถ€์กฑยท์šฐ์—ฐ ์Šน๋ฅ  ๋ฐฉ์ง€). ์ด๋ณด๋‹ค ์ ์€ ์กฐํ•ฉ์€ ํ•™์Šต/ํ›„๋ณด ์ง‘๊ณ„์—์„œ ์ œ์™ธ๋ฉ๋‹ˆ๋‹ค. +ํ•™์Šต์šฉ ํ†ต๊ณผ 180๊ฑด ยท ์‚ฌํ›„ํ•ฉ๊ฒฉ(results_gated) 161๊ฑด + +## ๊ณผ์ ํ•ฉยท์ ์šฉ ๊ฐ€๋Šฅ๋„ (ํœด๋ฆฌ์Šคํ‹ฑ) +- **๊ณผ์ ํ•ฉ ์œ„ํ—˜ 50.0%** ยท **์ ์šฉ ๊ฐ€๋Šฅ๋„ 50.0%** ยท ํŒ์ •: **์ฃผ์˜** โ€” ์ ์šฉ ๊ฐ€๋Šฅ๋„ ์ค‘๊ฐ„ โ€” ๋‹ค์ผ(โ‰ฅ5์ผ) ์žฌ๊ฒ€์ฆยท์›น๋ฐฑํ…Œ ํ›„ ์†Œ์•ก๋งŒ + - ํ‘œ๋ณธ ์žฅ์ผ: +40.0p โ€” ๊ฑฐ๋ž˜์ผโ‰ˆ1์ผ โ€” ๋‹จ์ผ ์žฅ ๊ณผ์ ํ•ฉ ์œ„ํ—˜ ์ตœ๋Œ€ + - ๊ฑฐ๋ž˜ ํ‘œ๋ณธ: +0.0p โ€” ์ƒ์œ„ ํ›„๋ณด ๊ฑฐ๋ž˜ 424๊ฑด โ€” ์ƒ๋Œ€์  ์–‘ํ˜ธ + - ์Šน๋ฅ ยทPF ์ด์ƒ์น˜: +0.0p โ€” ์ด์ƒ์น˜ ์—†์Œ + - ๊ฒŒ์ดํŠธ ์ปค๋ฒ„: +10.0p โ€” gated/all=161/180 โ€” ๋‹จ์ผ์— ๋Œ€๋ถ€๋ถ„ ํ†ต๊ณผ(ํ•„ํ„ฐ ๋А์Šจยท๋…ธ์ด์ฆˆ) + - PnL ๊ณ ์›: +0.0p โ€” ๊ณ ์› ๋น„์œจ 1% (1๊ฑด) +- ์ž„๊ณ„๊ฐ’ ๋ถ„ํฌ ํ‘œ๋ณธ: results_gated ์ƒ์œ„ 30๊ฑด +| ํŒŒ๋ผ๋ฏธํ„ฐ | median | p25~p75 | mode(๋น„์œจ) | +|---|---:|---|---| +| `rsi_period` | 3.0 | 3.0 ~ 3.0 | 3 (83%) | +| `rsi_oversold` | 18.5 | 16.125 ~ 19.5 | 16.0 (17%) | +| `rsi_overbought` | 83.0 | 81.0 ~ 84.0 | 85.0 (17%) | +| `sl_pct` | 5.6 | 5.3 ~ 5.8 | 5.9 (20%) | +| `tp_pct` | 1.1 | 0.9 ~ 1.5 | 1.0 (17%) | +| `tp_max_pct` | 9.75 | 9.0 ~ 10.5 | 10.0 (20%) | +| `drop_rate` | 3.4 | 2.15 ~ 5.7 | 6.3 (10%) | +| `shoulder_min_high` | 3.0 | 2.6 ~ 3.475 | 2.7 (10%) | +| `shoulder_cut_pct` | 0.5 | 0.3 ~ 0.5375 | 0.5 (27%) | +| `cooldown_min` | 5.5 | 2.0 ~ 12.75 | 2 (13%) | +| `high_chase_thr` | 0.975 | 0.97 ~ 0.975 | 0.975 (37%) | +| `max_daily_chg` | 26.5 | 16.25 ~ 29.75 | 28.0 (13%) | +- _์ฐธ๊ณ : ๊ณผ์ ํ•ฉ%๋Š” ๊ต์ฐจ๊ฒ€์ฆ ์ ์ˆ˜๊ฐ€ ์•„๋‹ˆ๋ผ ํ‘œ๋ณธยท์ด์ƒ์น˜ยท๊ณ ์› ํœด๋ฆฌ์Šคํ‹ฑ์ž…๋‹ˆ๋‹ค. ์ ์šฉ ๊ฐ€๋Šฅ๋„%=100โˆ’๊ณผ์ ํ•ฉ์œ„ํ—˜%. DB ์ ์šฉ ๋ฒ„ํŠผ ํ™œ์„ฑ ์กฐ๊ฑด(gated PnL>0)๊ณผ๋Š” ๋ณ„๊ฐœ์ž…๋‹ˆ๋‹ค._ + +## ์ตœ์ข… ์„ ํƒ ํ›„๋ณด (๊ทœ์น™ ยท DB ์ ์šฉ ์ „ ํ™•์ธ) +- ์•„๋ž˜๋Š” **์—ญํ• ์ด ๋‹ค๋ฅธ** 4์ข… ํ›„๋ณด์ž…๋‹ˆ๋‹ค. mode Top10 1์œ„ โ‰  ์ต์ ˆ ๋Œ€ํ‘œ ยท **DB 1์ˆœ์œ„๋Š” ์‚ฌํ›„ํ•ฉ๊ฒฉ(gated)** ์ž…๋‹ˆ๋‹ค. +- mode pool: `positive` ยท scoring: `band_proximity_p25_p75` + +### ํ›„๋ณด 4์ข… +- **โ‘  ์‚ฌํ›„ํ•ฉ๊ฒฉ 1์œ„ (apply: gated)** (trial #67): PnL 50,792์› ยท WR 69.6% ยท PF 3.02 ยท ๊ฑฐ๋ž˜ 424๊ฑด ยท ์•ˆ์ •์ ์ˆ˜ 2028 ยท ํ˜ธ๊ฐ€ON spr7.1 r0.35 askร—62 ยท ์ต์ ˆ1.0% ์ƒํ•œ11.0% ์†์ ˆ5.7% ยท ํœฉ์˜OFF +- **โ‘ก ์•ˆ์ • 1์œ„ (apply: stable)** (trial #133): PnL 44,245์› ยท WR 74.5% ยท PF 2.59 ยท ๊ฑฐ๋ž˜ 466๊ฑด ยท ์•ˆ์ •์ ์ˆ˜ 4192 ยท ํ˜ธ๊ฐ€OFF ยท ์ต์ ˆ0.8% ์ƒํ•œ7.5% ์†์ ˆ5.3% ยท ํœฉ์˜OFF +- **โ‘ข mode_combo (apply: mode)** (trial ์—†์Œ(์กฐ๋ฆฝ)): PnL 49,111์› ยท WR 69.6% ยท PF 2.95 ยท ๊ฑฐ๋ž˜ 421๊ฑด ยท ์•ˆ์ •์ ์ˆ˜ 2049 ยท ํ˜ธ๊ฐ€OFF ยท ์ต์ ˆ1.0% ์ƒํ•œ12.0% ์†์ ˆ5.9% ยท ํœฉ์˜OFF ยท tp ์ตœ๋นˆ 1.0% (12/165) +- **โ‘ฃ mode Top10 1์œ„ (apply: consensus ยท ๋ฐด๋“œ ์ „ํ˜• trial)** (trial #115): PnL 50,244์› ยท WR 71.9% ยท PF 2.88 ยท ๊ฑฐ๋ž˜ 452๊ฑด ยท ์•ˆ์ •์ ์ˆ˜ 1301 ยท ๊ทผ์ ‘ 99.8% (29/30์ถ• ๋ฐด๋“œ์•ˆ) ยท ํ˜ธ๊ฐ€OFF ยท ์ต์ ˆ0.9% ์ƒํ•œ11.0% ์†์ ˆ5.6% ยท ํœฉ์˜OFF + +- mode pool tp_pct ๋ฐด๋“œ p25~p75: **0.9~2.5%** ยท Top10 1์œ„ tp=0.9% โ†’ ๋ฐด๋“œ **์•ˆ** +- mode Top10 meta: pool 165๊ฑด ยท ์ถ• 30๊ฐœ + +### ์ถ”์ฒœ (์ž๋™ ยท confirm ํ•„์ˆ˜) +1. **์‹ค๋งค DB ์ ์šฉ 1์ˆœ์œ„ โ†’ โ‘  ์‚ฌํ›„ํ•ฉ๊ฒฉ 1์œ„** (`optunaApply gated`) โ€” WR/PFยทmin_trades ์‚ฌํ›„ ํ†ต๊ณผ. +2. **๋ณ€๋™์„ฑยท์†์‹ค์ผ ์ค„์ด๊ธฐ โ†’ โ‘ก ์•ˆ์ • 1์œ„** (`stable`) โ€” PnL๋ณด๋‹ค ์ผ๋ณ„ ์•ˆ์ • ์šฐ์„  ์‹œ. +3. **2์ฐจ narrowยท๋Œ€ํ‘œ ์ˆซ์ž โ†’ โ‘ข mode_combo** โ€” ์ถ•๋ณ„ ์ตœ๋นˆ ์กฐ๋ฆฝ ยท trial ๋ฒˆํ˜ธ ์—†์Œ ยท ์ต์ ˆ์€ pool ์ตœ๋นˆ๊ฐ’ ์ฐธ๊ณ . +4. **โ‘ฃ mode Top10 1์œ„** โ€” ์–‘์ˆ˜ pool ์ „ํ˜• trial(๋‹ค์ถ• ๋ฐด๋“œ ๊ทผ์ ‘). **์ต์ ˆ ํ•˜๋‚˜๋กœ ์“ฐ์ง€ ๋ง ๊ฒƒ** ยท ํ‘œ์—์„œ ใ€Œ๋ณด๊ธฐใ€โ†’ consensus apply. + +## ์ด์ „ ์žฅ์—์„œ๋Š” +- ์‹ค๋งค ๋™๊ธฐ๊ฐ„ ์ฒญ์‚ฐ 10๊ฑด ยท ์Šน๋ฅ  40% ยท ํ•ฉ์‚ฐ PnL -14,349์› (๋ฐฑํ…Œ Optuna์™€ ์ˆซ์ž ๋‹ฌ๋ผ๋„ ์ •์ƒ โ€” ๊ณ ์ŠคํŠธยท์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑ ๊ฒฝ๋กœ ์ฐจ์ด). +- ์‚ฌํ›„ํ•ฉ๊ฒฉ 1์œ„: trial #67 ยท ๊ฑฐ๋ž˜ 424๊ฑด ยท ์Šน๋ฅ  69.6% ยท PF 3.02 ยท PnL 50,792์› +- ํ‘œ๋ณธ ์žฅ์ด 1์ผ๋ฟ์ด๋ผ, โ€˜์ด์ „ ์žฅ์— ์ž˜ ๋จนํžŒ ์ˆซ์žโ€™์ผ ๋ฟ **์ถ”์„ธ๊ฐ€ ๋ฐ”๋€Œ๋ฉด ๋ฐ”๋กœ ๊นจ์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.** + +## ์•ž์œผ๋กœ ์žฅ์—์„œ๋Š” +- **1~2์ผ Optuna best๋ฅผ ๋ฐ”๋กœ ์‹ค๋งค์— ๋„ฃ์ง€ ๋งˆ์„ธ์š”.** ๋‹ค์ผ(โ‰ฅ5๊ฑฐ๋ž˜์ผ) ์žฌ๊ฒ€์ฆยท์›น๋ฐฑํ…Œ 1ํšŒ ํ›„ ๊ฒ€ํ† . +- ์ ์šฉ ์‹œ์—๋Š” `results_gated` ํ›„๋ณด๋งŒ. ํƒ์ƒ‰์šฉ best(objective)์™€ ๋‹ค๋ฅผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. +- ์žฅ์ด ์ข์•„์ง€๊ฑฐ๋‚˜ ๋ณ€๋™์„ฑ์ด ์ปค์ง€๋ฉด: ์†์ ˆยทํŠธ๋ ˆ์ผยท์‹œ๊ฐ„์ฐฝ์ด ๋จผ์ € ๊นจ์ง‘๋‹ˆ๋‹ค. ์Šน๋ฅ  ์ž๋ž‘๋ณด๋‹ค **์†์ ˆ์ด ์‚ด์•„ ์žˆ๋Š”์ง€**๋ฅผ ๋ณด์„ธ์š”. +- ์‚ฌํ›„ํ•ฉ๊ฒฉ์ด ์žˆ์–ด๋„ โ€˜๋‚ด์ผ๋„ ๊ฐ™์€ ์žฅโ€™์ด ์•„๋‹™๋‹ˆ๋‹ค. ํŽ˜์ดํผ/์†Œ์•กยท๋ชจ์˜๋กœ 1~2์ผ ๊ด€์ฐฐ ํ›„ ํ™•๋Œ€ํ•˜์„ธ์š”. + +_์ƒ์„ฑ: 2026-09-05 01:47:15 (rule)_ + +## AI ์ฝ”๋ฉ˜ํŠธ (์ด์ „ ์žฅ / ์•ž์œผ๋กœ ์žฅ) [gemini] + +๋‹น์‹ ์€ ํ•œ๊ตญ ์ฃผ์‹ ํ€€ํŠธ ํ—ค์ง€ํŽ€๋“œ ๋ฆฌ์Šคํฌ ๋งค๋‹ˆ์ €์ž…๋‹ˆ๋‹ค. ์•„๋ž˜ Optuna TPE ๊ฒฐ๊ณผ์™€ ๊ทœ์น™ ๋ธŒ๋ฆฌํ•‘์„ ์ฝ๊ณ , ์ดˆ๋ณด์ž๋„ ์ดํ•ดํ•˜๊ฒŒ ใ€Œ์ด์ „ ์žฅ์—์„œ๋Š”ใ€/ใ€Œ์•ž์œผ๋กœ ์žฅ์—์„œ๋Š”ใ€ ๋‘ ์ ˆ๋กœ๋งŒ ํ•œ๊ตญ์–ด ์ฝ”๋ฉ˜ํŠธ๋ฅผ ์“ฐ์„ธ์š”. ๊ณผ์ ํ•ฉยทํ‘œ๋ณธ๋ถ€์กฑยท์‹ค๋งคโ†”๋ฐฑํ…Œ ๊ดด๋ฆฌ(๊ณ ์ŠคํŠธํผ์ง€ ๋“ฑ)๋ฅผ ๋ถ„๋ช…ํžˆ ๊ฒฝ๊ณ ํ•˜์„ธ์š”. mode Top10 1์œ„๋ฅผ ์ต์ ˆ ๋Œ€ํ‘œ๋กœ ๋‹จ์ •ํ•˜์ง€ ๋งˆ์„ธ์š” โ€” DB 1์ˆœ์œ„๋Š” ์‚ฌํ›„ํ•ฉ๊ฒฉ(gated). ํŠน์ • ์ข…๋ชฉ ๋งค์ˆ˜ ์ถ”์ฒœยทํ™•์ • ์ˆ˜์ต ์•ฝ์† ๊ธˆ์ง€. 200~400์ž. + +*** + +### ์ด์ „ ์žฅ์—์„œ๋Š” +์ง€๋‚œ 9์›” 4์ผ ๋‹จ ํ•˜๋ฃจ ๋ฐฑํ…Œ์ŠคํŠธ์—์„œ ์‚ฌํ›„ํ•ฉ๊ฒฉ 1์œ„ ์ „๋žต(trial #67)์€ PnL ์•ฝ 5๋งŒ์›, ์Šน๋ฅ  ์•ฝ 70%๋กœ ์šฐ์ˆ˜ํ•œ ๊ฒฐ๊ณผ์ฒ˜๋Ÿผ ๋ณด์˜€์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ๊ฐ™์€ ๊ธฐ๊ฐ„ ์‹ค์ œ ๋งค๋งค๋Š” 10๊ฑด ์ค‘ 40% ์Šน๋ฅ ๋กœ ์•ฝ 1.4๋งŒ์› ์†์‹ค์„ ๊ธฐ๋กํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š” ๋ฐฑํ…Œ์ŠคํŠธ์™€ ์‹ค์ œ ์‹œ์žฅ ํ™˜๊ฒฝ(ํ˜ธ๊ฐ€์ฐฝ, ์ฒด๊ฒฐ ์ง€์—ฐ ๋“ฑ) ๊ฐ„์˜ ๊ดด๋ฆฌ๋ฅผ ๋ช…ํ™•ํžˆ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค. ๋‹จ์ผ ๊ฑฐ๋ž˜์ผ ๋ถ„์„์€ ํŠน์ • ์žฅ์„ธ์— ๊ณผ์ ํ•ฉ๋˜์—ˆ์„ ์œ„ํ—˜์ด ๋งค์šฐ ๋†’์Šต๋‹ˆ๋‹ค. + +### ์•ž์œผ๋กœ ์žฅ์—์„œ๋Š” +์ด์ฒ˜๋Ÿผ ๋‹จ์ผ ๊ฑฐ๋ž˜์ผ ๋ฐฑํ…Œ์ŠคํŠธ๋Š” ๊ณผ์ ํ•ฉ ์œ„ํ—˜ 50%๋กœ โ€˜์ฃผ์˜โ€™ ํŒ์ •์ž…๋‹ˆ๋‹ค. ํ‘œ๋ณธ ๋ถ€์กฑ๊ณผ ์‹ค๋งค ๊ดด๋ฆฌ๋ฅผ ๊ฐ„๊ณผํ•œ ์ฆ‰๊ฐ์ ์ธ ์ ์šฉ์€ ํฐ ์†์‹ค๋กœ ์ด์–ด์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. DB ์ ์šฉ 1์ˆœ์œ„๋Š” ์‚ฌํ›„ํ•ฉ๊ฒฉ๋œ ์ „๋žต(#67)์ด์ง€๋งŒ, mode Top10 1์œ„์ฒ˜๋Ÿผ ํŠน์ • ์ต์ ˆ ๋Œ€ํ‘œ๊ฐ’์œผ๋กœ ๋‹จ์ •ํ•˜์—ฌ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ๋ฐ˜๋“œ์‹œ 5์ผ ์ด์ƒ์˜ ๋‹ค์ผ ์žฌ๊ฒ€์ฆ๊ณผ ์›น๋ฐฑํ…Œ์ŠคํŠธ๋ฅผ ๊ฑฐ์น˜๊ณ , ํŽ˜์ดํผ/์†Œ์•ก ๋ชจ์˜ํˆฌ์ž๋กœ ์‹ค์ œ ์‹œ์žฅ ๋ฐ˜์‘์„ ํ™•์ธ ํ›„ ์ ์šฉ์„ ๊ณ ๋ คํ•˜์„ธ์š”. ํŠน์ • ์ข…๋ชฉ ๋งค์ˆ˜ ์ถ”์ฒœ์ด๋‚˜ ํ™•์ • ์ˆ˜์ต์„ ์•ฝ์†ํ•  ์ˆ˜ ์—†์œผ๋ฉฐ, ์‹œ์žฅ ๋ณ€ํ™” ์‹œ ์†์ ˆ ๊ธฐ์ค€์ด ์‚ด์•„์žˆ๋Š”์ง€ ํ™•์ธ์ด ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค. diff --git a/kis_trader/backtest/results/optuna_scalp_tpe_20260905_015030.briefing.md b/kis_trader/backtest/results/optuna_scalp_tpe_20260905_015030.briefing.md new file mode 100644 index 0000000..272076a --- /dev/null +++ b/kis_trader/backtest/results/optuna_scalp_tpe_20260905_015030.briefing.md @@ -0,0 +1,71 @@ +# Optuna ๋ธŒ๋ฆฌํ•‘ โ€” ์Šค์บ˜ํ•‘ (tpe) +๊ธฐ๊ฐ„: 2026-09-04 ~ 2026-09-04 (๊ฑฐ๋ž˜์ผโ‰ˆ1์ผ) ยท trials 200/200 +ํƒ์ƒ‰ ๊ฒŒ์ดํŠธ: WRโ‰ฅ0% PFโ‰ฅ0 ยท min_tradesโ‰ฅ2 | ํ›„๋ณด ๊ฒŒ์ดํŠธ: WRโ‰ฅ40% PFโ‰ฅ1 ยท min_tradesโ‰ฅ2 +- min_trades=2: **ํ•ฉ๊ฒฉ ์ธ์ • ์ตœ์†Œ ๊ฑฐ๋ž˜ ๊ฑด์ˆ˜**(ํ‘œ๋ณธ ๋ถ€์กฑยท์šฐ์—ฐ ์Šน๋ฅ  ๋ฐฉ์ง€). ์ด๋ณด๋‹ค ์ ์€ ์กฐํ•ฉ์€ ํ•™์Šต/ํ›„๋ณด ์ง‘๊ณ„์—์„œ ์ œ์™ธ๋ฉ๋‹ˆ๋‹ค. +ํ•™์Šต์šฉ ํ†ต๊ณผ 180๊ฑด ยท ์‚ฌํ›„ํ•ฉ๊ฒฉ(results_gated) 168๊ฑด + +## ๊ณผ์ ํ•ฉยท์ ์šฉ ๊ฐ€๋Šฅ๋„ (ํœด๋ฆฌ์Šคํ‹ฑ) +- **๊ณผ์ ํ•ฉ ์œ„ํ—˜ 50.0%** ยท **์ ์šฉ ๊ฐ€๋Šฅ๋„ 50.0%** ยท ํŒ์ •: **์ฃผ์˜** โ€” ์ ์šฉ ๊ฐ€๋Šฅ๋„ ์ค‘๊ฐ„ โ€” ๋‹ค์ผ(โ‰ฅ5์ผ) ์žฌ๊ฒ€์ฆยท์›น๋ฐฑํ…Œ ํ›„ ์†Œ์•ก๋งŒ + - ํ‘œ๋ณธ ์žฅ์ผ: +40.0p โ€” ๊ฑฐ๋ž˜์ผโ‰ˆ1์ผ โ€” ๋‹จ์ผ ์žฅ ๊ณผ์ ํ•ฉ ์œ„ํ—˜ ์ตœ๋Œ€ + - ๊ฑฐ๋ž˜ ํ‘œ๋ณธ: +0.0p โ€” ์ƒ์œ„ ํ›„๋ณด ๊ฑฐ๋ž˜ 361๊ฑด โ€” ์ƒ๋Œ€์  ์–‘ํ˜ธ + - ์Šน๋ฅ ยทPF ์ด์ƒ์น˜: +0.0p โ€” ์ด์ƒ์น˜ ์—†์Œ + - ๊ฒŒ์ดํŠธ ์ปค๋ฒ„: +10.0p โ€” gated/all=168/180 โ€” ๋‹จ์ผ์— ๋Œ€๋ถ€๋ถ„ ํ†ต๊ณผ(ํ•„ํ„ฐ ๋А์Šจยท๋…ธ์ด์ฆˆ) + - PnL ๊ณ ์›: +0.0p โ€” ๊ณ ์› ๋น„์œจ 1% (1๊ฑด) +- ์ž„๊ณ„๊ฐ’ ๋ถ„ํฌ ํ‘œ๋ณธ: results_gated ์ƒ์œ„ 30๊ฑด +| ํŒŒ๋ผ๋ฏธํ„ฐ | median | p25~p75 | mode(๋น„์œจ) | +|---|---:|---|---| +| `rsi_period` | 3.0 | 3.0 ~ 4.0 | 3 (67%) | +| `rsi_oversold` | 17.75 | 16.5 ~ 20.0 | 16.5 (13%) | +| `rsi_overbought` | 75.5 | 73.0 ~ 77.375 | 76.0 (17%) | +| `sl_pct` | 5.65 | 5.3 ~ 5.8 | 5.8 (23%) | +| `tp_pct` | 1.3 | 0.8 ~ 1.475 | 1.3 (17%) | +| `tp_max_pct` | 7.5 | 5.125 ~ 8.375 | 8.0 (17%) | +| `drop_rate` | 5.05 | 2.85 ~ 6.175 | 0.8 (7%) | +| `shoulder_min_high` | 0.7 | 0.3 ~ 0.875 | 0.3 (30%) | +| `shoulder_cut_pct` | 0.5 | 0.45 ~ 0.55 | 0.5 (40%) | +| `cooldown_min` | 1.0 | 0.0 ~ 2.0 | 0 (50%) | +| `high_chase_thr` | 0.985 | 0.97625 ~ 0.99 | 0.985 (27%) | +| `max_daily_chg` | 36.5 | 34.0 ~ 41.0 | 35.0 (13%) | +- _์ฐธ๊ณ : ๊ณผ์ ํ•ฉ%๋Š” ๊ต์ฐจ๊ฒ€์ฆ ์ ์ˆ˜๊ฐ€ ์•„๋‹ˆ๋ผ ํ‘œ๋ณธยท์ด์ƒ์น˜ยท๊ณ ์› ํœด๋ฆฌ์Šคํ‹ฑ์ž…๋‹ˆ๋‹ค. ์ ์šฉ ๊ฐ€๋Šฅ๋„%=100โˆ’๊ณผ์ ํ•ฉ์œ„ํ—˜%. DB ์ ์šฉ ๋ฒ„ํŠผ ํ™œ์„ฑ ์กฐ๊ฑด(gated PnL>0)๊ณผ๋Š” ๋ณ„๊ฐœ์ž…๋‹ˆ๋‹ค._ + +## ์ตœ์ข… ์„ ํƒ ํ›„๋ณด (๊ทœ์น™ ยท DB ์ ์šฉ ์ „ ํ™•์ธ) +- ์•„๋ž˜๋Š” **์—ญํ• ์ด ๋‹ค๋ฅธ** 4์ข… ํ›„๋ณด์ž…๋‹ˆ๋‹ค. mode Top10 1์œ„ โ‰  ์ต์ ˆ ๋Œ€ํ‘œ ยท **DB 1์ˆœ์œ„๋Š” ์‚ฌํ›„ํ•ฉ๊ฒฉ(gated)** ์ž…๋‹ˆ๋‹ค. +- mode pool: `positive` ยท scoring: `band_proximity_p25_p75` + +### ํ›„๋ณด 4์ข… +- **โ‘  ์‚ฌํ›„ํ•ฉ๊ฒฉ 1์œ„ (apply: gated)** (trial #198): PnL 47,190์› ยท WR 63.2% ยท PF 2.75 ยท ๊ฑฐ๋ž˜ 361๊ฑด ยท ์•ˆ์ •์ ์ˆ˜ 567 ยท ํ˜ธ๊ฐ€OFF ยท ์ต์ ˆ1.3% ์ƒํ•œ6.5% ์†์ ˆ5.4% ยท ํœฉ์˜ON sub45s lb120s dip0.10% tol0.20% +- **โ‘ก ์•ˆ์ • 1์œ„ (apply: stable)** (trial #20): PnL 14,372์› ยท WR 82.4% ยท PF 3.74 ยท ๊ฑฐ๋ž˜ 108๊ฑด ยท ์•ˆ์ •์ ์ˆ˜ 5977 ยท ํ˜ธ๊ฐ€OFF ยท ์ต์ ˆ0.8% ์ƒํ•œ4.5% ์†์ ˆ4.1% ยท ํœฉ์˜OFF +- **โ‘ข mode_combo (apply: mode)** (trial ์—†์Œ(์กฐ๋ฆฝ)): PnL 45,442์› ยท WR 65.3% ยท PF 2.92 ยท ๊ฑฐ๋ž˜ 334๊ฑด ยท ์•ˆ์ •์ ์ˆ˜ 1455 ยท ํ˜ธ๊ฐ€OFF ยท ์ต์ ˆ1.3% ์ƒํ•œ7.5% ์†์ ˆ5.7% ยท ํœฉ์˜ON sub45s lb180s dip0.30% tol0.15% ยท tp ์ตœ๋นˆ 1.3% (12/169) +- **โ‘ฃ mode Top10 1์œ„ (apply: consensus ยท ๋ฐด๋“œ ์ „ํ˜• trial)** (trial #83): PnL 44,515์› ยท WR 60.2% ยท PF 2.29 ยท ๊ฑฐ๋ž˜ 377๊ฑด ยท ์•ˆ์ •์ ์ˆ˜ 1726 ยท ๊ทผ์ ‘ 99.0% (28/30์ถ• ๋ฐด๋“œ์•ˆ) ยท ํ˜ธ๊ฐ€OFF ยท ์ต์ ˆ1.5% ์ƒํ•œ6.5% ์†์ ˆ5.3% ยท ํœฉ์˜ON sub60s lb120s dip0.30% tol0.15% + +- mode pool tp_pct ๋ฐด๋“œ p25~p75: **0.9~2.2%** ยท Top10 1์œ„ tp=1.5% โ†’ ๋ฐด๋“œ **์•ˆ** +- mode Top10 meta: pool 169๊ฑด ยท ์ถ• 30๊ฐœ + +### ์ถ”์ฒœ (์ž๋™ ยท confirm ํ•„์ˆ˜) +1. **์‹ค๋งค DB ์ ์šฉ 1์ˆœ์œ„ โ†’ โ‘  ์‚ฌํ›„ํ•ฉ๊ฒฉ 1์œ„** (`optunaApply gated`) โ€” WR/PFยทmin_trades ์‚ฌํ›„ ํ†ต๊ณผ. +2. **๋ณ€๋™์„ฑยท์†์‹ค์ผ ์ค„์ด๊ธฐ โ†’ โ‘ก ์•ˆ์ • 1์œ„** (`stable`) โ€” PnL๋ณด๋‹ค ์ผ๋ณ„ ์•ˆ์ • ์šฐ์„  ์‹œ. +3. **2์ฐจ narrowยท๋Œ€ํ‘œ ์ˆซ์ž โ†’ โ‘ข mode_combo** โ€” ์ถ•๋ณ„ ์ตœ๋นˆ ์กฐ๋ฆฝ ยท trial ๋ฒˆํ˜ธ ์—†์Œ ยท ์ต์ ˆ์€ pool ์ตœ๋นˆ๊ฐ’ ์ฐธ๊ณ . +4. **โ‘ฃ mode Top10 1์œ„** โ€” ์–‘์ˆ˜ pool ์ „ํ˜• trial(๋‹ค์ถ• ๋ฐด๋“œ ๊ทผ์ ‘). **์ต์ ˆ ํ•˜๋‚˜๋กœ ์“ฐ์ง€ ๋ง ๊ฒƒ** ยท ํ‘œ์—์„œ ใ€Œ๋ณด๊ธฐใ€โ†’ consensus apply. + +## ์ด์ „ ์žฅ์—์„œ๋Š” +- ์‹ค๋งค ๋™๊ธฐ๊ฐ„ ์ฒญ์‚ฐ 10๊ฑด ยท ์Šน๋ฅ  40% ยท ํ•ฉ์‚ฐ PnL -14,349์› (๋ฐฑํ…Œ Optuna์™€ ์ˆซ์ž ๋‹ฌ๋ผ๋„ ์ •์ƒ โ€” ๊ณ ์ŠคํŠธยท์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑ ๊ฒฝ๋กœ ์ฐจ์ด). +- ์‚ฌํ›„ํ•ฉ๊ฒฉ 1์œ„: trial #198 ยท ๊ฑฐ๋ž˜ 361๊ฑด ยท ์Šน๋ฅ  63.2% ยท PF 2.75 ยท PnL 47,190์› +- ํ‘œ๋ณธ ์žฅ์ด 1์ผ๋ฟ์ด๋ผ, โ€˜์ด์ „ ์žฅ์— ์ž˜ ๋จนํžŒ ์ˆซ์žโ€™์ผ ๋ฟ **์ถ”์„ธ๊ฐ€ ๋ฐ”๋€Œ๋ฉด ๋ฐ”๋กœ ๊นจ์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.** + +## ์•ž์œผ๋กœ ์žฅ์—์„œ๋Š” +- **1~2์ผ Optuna best๋ฅผ ๋ฐ”๋กœ ์‹ค๋งค์— ๋„ฃ์ง€ ๋งˆ์„ธ์š”.** ๋‹ค์ผ(โ‰ฅ5๊ฑฐ๋ž˜์ผ) ์žฌ๊ฒ€์ฆยท์›น๋ฐฑํ…Œ 1ํšŒ ํ›„ ๊ฒ€ํ† . +- ์ ์šฉ ์‹œ์—๋Š” `results_gated` ํ›„๋ณด๋งŒ. ํƒ์ƒ‰์šฉ best(objective)์™€ ๋‹ค๋ฅผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. +- ์žฅ์ด ์ข์•„์ง€๊ฑฐ๋‚˜ ๋ณ€๋™์„ฑ์ด ์ปค์ง€๋ฉด: ์†์ ˆยทํŠธ๋ ˆ์ผยท์‹œ๊ฐ„์ฐฝ์ด ๋จผ์ € ๊นจ์ง‘๋‹ˆ๋‹ค. ์Šน๋ฅ  ์ž๋ž‘๋ณด๋‹ค **์†์ ˆ์ด ์‚ด์•„ ์žˆ๋Š”์ง€**๋ฅผ ๋ณด์„ธ์š”. +- ์‚ฌํ›„ํ•ฉ๊ฒฉ์ด ์žˆ์–ด๋„ โ€˜๋‚ด์ผ๋„ ๊ฐ™์€ ์žฅโ€™์ด ์•„๋‹™๋‹ˆ๋‹ค. ํŽ˜์ดํผ/์†Œ์•กยท๋ชจ์˜๋กœ 1~2์ผ ๊ด€์ฐฐ ํ›„ ํ™•๋Œ€ํ•˜์„ธ์š”. + +_์ƒ์„ฑ: 2026-09-05 01:50:31 (rule)_ + +## AI ์ฝ”๋ฉ˜ํŠธ (์ด์ „ ์žฅ / ์•ž์œผ๋กœ ์žฅ) [gemini] + +ํ€€ํŠธ ํ—ค์ง€ํŽ€๋“œ ๋ฆฌ์Šคํฌ ๋งค๋‹ˆ์ €๋กœ์„œ, Optuna TPE ๊ฒฐ๊ณผ๋ฅผ ๋ฐ”ํƒ•์œผ๋กœ ๋‹ค์Œ ์ฝ”๋ฉ˜ํŠธ๋ฅผ ๋“œ๋ฆฝ๋‹ˆ๋‹ค. + +ใ€Œ์ด์ „ ์žฅ์—์„œ๋Š”ใ€ +์ง€๋‚œ 1์ผ(2026-09-04) Optuna ์Šค์บ˜ํ•‘ ๋ฐฑํ…Œ์ŠคํŠธ์—์„œ ์‚ฌํ›„ํ•ฉ๊ฒฉ 1์œ„๋Š” PnL 4.7๋งŒ์›, WR 63.2%๋ฅผ ๊ธฐ๋กํ–ˆ์œผ๋‚˜, ๋™์ผ ๊ธฐ๊ฐ„ ์‹ค๋งค๋Š” -1.4๋งŒ์›์œผ๋กœ ํฐ ๊ดด๋ฆฌ๋ฅผ ๋ณด์˜€์Šต๋‹ˆ๋‹ค. ์ด๋Š” ๋‹จ์ผ ์žฅ ๋ฐ์ดํ„ฐ๋กœ ์ธํ•œ ๊ณผ์ ํ•ฉ ์œ„ํ—˜ 50%์˜ '์ฃผ์˜' ํŒ์ • ๊ฒฐ๊ณผ์ด๋ฉฐ, ๊ณ ์ŠคํŠธํผ์ง€ ๋“ฑ ๋ฐฑํ…Œ์ŠคํŠธ์™€ ์‹ค๋งค ๊ฐ„์˜ ์ฐจ์ด๋ฅผ ๋ช…ํ™•ํžˆ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค. DB 1์ˆœ์œ„๋Š” ์‚ฌํ›„ํ•ฉ๊ฒฉ(gated)๋œ ์กฐํ•ฉ์ด๋ฉฐ, mode Top10 1์œ„๋Š” ์ต์ ˆ ๋Œ€ํ‘œ๊ฐ€ ์•„๋‹Œ ํŒŒ๋ผ๋ฏธํ„ฐ ๋ฐด๋“œ ๋‚ด ์ „ํ˜•์  ํ›„๋ณด์ž„์„ ๊ธฐ์–ตํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. + +ใ€Œ์•ž์œผ๋กœ ์žฅ์—์„œ๋Š”ใ€ +์ด๋ฒˆ 1์ผ ๋ฐฑํ…Œ์ŠคํŠธ ๊ฒฐ๊ณผ๋Š” ๊ณผ์ ํ•ฉ ์œ„ํ—˜์ด ๋†’์•„ ์ ˆ๋Œ€ ๋ฐ”๋กœ ์‹ค๋งค์— ์ ์šฉํ•ด์„œ๋Š” ์•ˆ ๋ฉ๋‹ˆ๋‹ค. ์ตœ์†Œ 5๊ฑฐ๋ž˜์ผ ์ด์ƒ ๋‹ค์ผ ์žฌ๊ฒ€์ฆ๊ณผ ์›น ๋ฐฑํ…Œ์ŠคํŠธ ํ›„, ์†Œ์•กยท๋ชจ์˜ ํˆฌ์ž๋กœ ์ถฉ๋ถ„ํžˆ ๊ด€์ฐฐํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๋ฐฑํ…Œ์ŠคํŠธ ์ˆ˜์น˜๋Š” ๋ฏธ๋ž˜ ์ˆ˜์ต์„ ๋ณด์žฅํ•˜์ง€ ์•Š์œผ๋ฉฐ, ์‹ค๋งค ์‹œ ๊ณ ์ŠคํŠธํผ์ง€ ๋“ฑ์œผ๋กœ ๊ดด๋ฆฌ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์‹œ์žฅ ์ƒํ™ฉ ๋ณ€ํ™” ์‹œ ์ˆ˜์ต๋ฅ ๋ณด๋‹ค ์†์ ˆ๋งค๊ฐ€ ์ œ๋Œ€๋กœ ์ž‘๋™ํ•˜๋Š”์ง€ ์šฐ์„  ์ ๊ฒ€ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ํŠน์ • ์ข…๋ชฉ ์ถ”์ฒœ์ด๋‚˜ ํ™•์ • ์ˆ˜์ต ์•ฝ์†์€ ๋ถˆ๊ฐ€ํ•ฉ๋‹ˆ๋‹ค. diff --git a/kis_trader/backtest/results/optuna_scalp_tpe_20260906_131223.briefing.md b/kis_trader/backtest/results/optuna_scalp_tpe_20260906_131223.briefing.md new file mode 100644 index 0000000..d89e6c7 --- /dev/null +++ b/kis_trader/backtest/results/optuna_scalp_tpe_20260906_131223.briefing.md @@ -0,0 +1,69 @@ +# Optuna ๋ธŒ๋ฆฌํ•‘ โ€” ์Šค์บ˜ํ•‘ (tpe) +๊ธฐ๊ฐ„: 2026-09-04 ~ 2026-09-04 (๊ฑฐ๋ž˜์ผโ‰ˆ1์ผ) ยท trials 200/200 +ํƒ์ƒ‰ ๊ฒŒ์ดํŠธ: WRโ‰ฅ0% PFโ‰ฅ0 ยท min_tradesโ‰ฅ2 | ํ›„๋ณด ๊ฒŒ์ดํŠธ: WRโ‰ฅ40% PFโ‰ฅ1 ยท min_tradesโ‰ฅ2 +- min_trades=2: **ํ•ฉ๊ฒฉ ์ธ์ • ์ตœ์†Œ ๊ฑฐ๋ž˜ ๊ฑด์ˆ˜**(ํ‘œ๋ณธ ๋ถ€์กฑยท์šฐ์—ฐ ์Šน๋ฅ  ๋ฐฉ์ง€). ์ด๋ณด๋‹ค ์ ์€ ์กฐํ•ฉ์€ ํ•™์Šต/ํ›„๋ณด ์ง‘๊ณ„์—์„œ ์ œ์™ธ๋ฉ๋‹ˆ๋‹ค. +ํ•™์Šต์šฉ ํ†ต๊ณผ 185๊ฑด ยท ์‚ฌํ›„ํ•ฉ๊ฒฉ(results_gated) 171๊ฑด + +## ๊ณผ์ ํ•ฉยท์ ์šฉ ๊ฐ€๋Šฅ๋„ (ํœด๋ฆฌ์Šคํ‹ฑ) +- **๊ณผ์ ํ•ฉ ์œ„ํ—˜ 50.0%** ยท **์ ์šฉ ๊ฐ€๋Šฅ๋„ 50.0%** ยท ํŒ์ •: **์ฃผ์˜** โ€” ์ ์šฉ ๊ฐ€๋Šฅ๋„ ์ค‘๊ฐ„ โ€” ๋‹ค์ผ(โ‰ฅ5์ผ) ์žฌ๊ฒ€์ฆยท์›น๋ฐฑํ…Œ ํ›„ ์†Œ์•ก๋งŒ + - ํ‘œ๋ณธ ์žฅ์ผ: +40.0p โ€” ๊ฑฐ๋ž˜์ผโ‰ˆ1์ผ โ€” ๋‹จ์ผ ์žฅ ๊ณผ์ ํ•ฉ ์œ„ํ—˜ ์ตœ๋Œ€ + - ๊ฑฐ๋ž˜ ํ‘œ๋ณธ: +0.0p โ€” ์ƒ์œ„ ํ›„๋ณด ๊ฑฐ๋ž˜ 469๊ฑด โ€” ์ƒ๋Œ€์  ์–‘ํ˜ธ + - ์Šน๋ฅ ยทPF ์ด์ƒ์น˜: +0.0p โ€” ์ด์ƒ์น˜ ์—†์Œ + - ๊ฒŒ์ดํŠธ ์ปค๋ฒ„: +10.0p โ€” gated/all=171/185 โ€” ๋‹จ์ผ์— ๋Œ€๋ถ€๋ถ„ ํ†ต๊ณผ(ํ•„ํ„ฐ ๋А์Šจยท๋…ธ์ด์ฆˆ) + - PnL ๊ณ ์›: +0.0p โ€” ๊ณ ์› ๋น„์œจ 1% (1๊ฑด) +- ์ž„๊ณ„๊ฐ’ ๋ถ„ํฌ ํ‘œ๋ณธ: results_gated ์ƒ์œ„ 30๊ฑด +| ํŒŒ๋ผ๋ฏธํ„ฐ | median | p25~p75 | mode(๋น„์œจ) | +|---|---:|---|---| +| `rsi_period` | 3.0 | 3.0 ~ 4.0 | 3 (60%) | +| `rsi_oversold` | 21.25 | 20.0 ~ 25.5 | 20.5 (17%) | +| `rsi_overbought` | 79.0 | 74.0 ~ 81.875 | 81.5 (13%) | +| `sl_pct` | 5.8 | 5.7 ~ 5.9 | 6.0 (23%) | +| `tp_pct` | 0.95 | 0.8 ~ 1.875 | 0.8 (17%) | +| `tp_max_pct` | 11.25 | 8.875 ~ 11.5 | 11.5 (30%) | +| `drop_rate` | 3.1 | 2.05 ~ 4.375 | 4.5 (10%) | +| `shoulder_min_high` | 1.8 | 1.6 ~ 2.3 | 1.6 (17%) | +| `shoulder_cut_pct` | 0.25 | 0.15 ~ 0.35 | 0.15 (27%) | +| `cooldown_min` | 8.0 | 7.0 ~ 9.0 | 9 (30%) | +| `high_chase_thr` | 0.99 | 0.985 ~ 1.0 | 1.0 (30%) | +| `max_daily_chg` | 29.0 | 25.0 ~ 33.5 | 30.0 (13%) | +- _์ฐธ๊ณ : ๊ณผ์ ํ•ฉ%๋Š” ๊ต์ฐจ๊ฒ€์ฆ ์ ์ˆ˜๊ฐ€ ์•„๋‹ˆ๋ผ ํ‘œ๋ณธยท์ด์ƒ์น˜ยท๊ณ ์› ํœด๋ฆฌ์Šคํ‹ฑ์ž…๋‹ˆ๋‹ค. ์ ์šฉ ๊ฐ€๋Šฅ๋„%=100โˆ’๊ณผ์ ํ•ฉ์œ„ํ—˜%. DB ์ ์šฉ ๋ฒ„ํŠผ ํ™œ์„ฑ ์กฐ๊ฑด(gated PnL>0)๊ณผ๋Š” ๋ณ„๊ฐœ์ž…๋‹ˆ๋‹ค._ + +## ์ตœ์ข… ์„ ํƒ ํ›„๋ณด (๊ทœ์น™ ยท DB ์ ์šฉ ์ „ ํ™•์ธ) +- ์•„๋ž˜๋Š” **์—ญํ• ์ด ๋‹ค๋ฅธ** 4์ข… ํ›„๋ณด์ž…๋‹ˆ๋‹ค. mode Top10 1์œ„ โ‰  ์ต์ ˆ ๋Œ€ํ‘œ ยท **DB 1์ˆœ์œ„๋Š” ์‚ฌํ›„ํ•ฉ๊ฒฉ(gated)** ์ž…๋‹ˆ๋‹ค. +- mode pool: `positive` ยท scoring: `band_proximity_p25_p75` + +### ํ›„๋ณด 4์ข… +- **โ‘  ์‚ฌํ›„ํ•ฉ๊ฒฉ 1์œ„ (apply: gated)** (trial #135): PnL 49,639์› ยท WR 74.4% ยท PF 3.02 ยท ๊ฑฐ๋ž˜ 469๊ฑด ยท ์•ˆ์ •์ ์ˆ˜ 2390 ยท ํ˜ธ๊ฐ€OFF ยท ์ต์ ˆ0.8% ์ƒํ•œ11.5% ์†์ ˆ6.0% ยท ํœฉ์˜OFF +- **โ‘ก ์•ˆ์ • 1์œ„ (apply: stable)** (trial #180): PnL 44,782์› ยท WR 68.1% ยท PF 2.39 ยท ๊ฑฐ๋ž˜ 445๊ฑด ยท ์•ˆ์ •์ ์ˆ˜ 3196 ยท ํ˜ธ๊ฐ€ON spr5.4 r0.05 askร—12 ยท ์ต์ ˆ1.0% ์ƒํ•œ11.0% ์†์ ˆ6.0% ยท ํœฉ์˜OFF +- **โ‘ข mode_combo (apply: mode)** (trial ์—†์Œ(์กฐ๋ฆฝ)): PnL 87,406์› ยท WR 77.7% ยท PF 2.44 ยท ๊ฑฐ๋ž˜ 949๊ฑด ยท ์•ˆ์ •์ ์ˆ˜ -4141 ยท ํ˜ธ๊ฐ€OFF ยท ์ต์ ˆ0.8% ์ƒํ•œ11.5% ์†์ ˆ6.0% ยท ํœฉ์˜OFF ยท tp ์ตœ๋นˆ 0.8% (12/175) +- **โ‘ฃ mode Top10 1์œ„ (apply: consensus ยท ๋ฐด๋“œ ์ „ํ˜• trial)** (trial #99): PnL 49,079์› ยท WR 56.3% ยท PF 2.53 ยท ๊ฑฐ๋ž˜ 311๊ฑด ยท ์•ˆ์ •์ ์ˆ˜ 903 ยท ๊ทผ์ ‘ 99.8% (31/32์ถ• ๋ฐด๋“œ์•ˆ) ยท ํ˜ธ๊ฐ€OFF ยท ์ต์ ˆ2.4% ์ƒํ•œ11.5% ์†์ ˆ5.8% ยท ํœฉ์˜OFF + +- mode pool tp_pct ๋ฐด๋“œ p25~p75: **0.9~2.7%** ยท Top10 1์œ„ tp=2.4% โ†’ ๋ฐด๋“œ **์•ˆ** +- mode Top10 meta: pool 175๊ฑด ยท ์ถ• 32๊ฐœ + +### ์ถ”์ฒœ (์ž๋™ ยท confirm ํ•„์ˆ˜) +1. **์‹ค๋งค DB ์ ์šฉ 1์ˆœ์œ„ โ†’ โ‘  ์‚ฌํ›„ํ•ฉ๊ฒฉ 1์œ„** (`optunaApply gated`) โ€” WR/PFยทmin_trades ์‚ฌํ›„ ํ†ต๊ณผ. +2. **๋ณ€๋™์„ฑยท์†์‹ค์ผ ์ค„์ด๊ธฐ โ†’ โ‘ก ์•ˆ์ • 1์œ„** (`stable`) โ€” PnL๋ณด๋‹ค ์ผ๋ณ„ ์•ˆ์ • ์šฐ์„  ์‹œ. +3. **2์ฐจ narrowยท๋Œ€ํ‘œ ์ˆซ์ž โ†’ โ‘ข mode_combo** โ€” ์ถ•๋ณ„ ์ตœ๋นˆ ์กฐ๋ฆฝ ยท trial ๋ฒˆํ˜ธ ์—†์Œ ยท ์ต์ ˆ์€ pool ์ตœ๋นˆ๊ฐ’ ์ฐธ๊ณ . +4. **โ‘ฃ mode Top10 1์œ„** โ€” ์–‘์ˆ˜ pool ์ „ํ˜• trial(๋‹ค์ถ• ๋ฐด๋“œ ๊ทผ์ ‘). **์ต์ ˆ ํ•˜๋‚˜๋กœ ์“ฐ์ง€ ๋ง ๊ฒƒ** ยท ํ‘œ์—์„œ ใ€Œ๋ณด๊ธฐใ€โ†’ consensus apply. + +## ์ด์ „ ์žฅ์—์„œ๋Š” +- ์‹ค๋งค ๋™๊ธฐ๊ฐ„ ์ฒญ์‚ฐ 10๊ฑด ยท ์Šน๋ฅ  40% ยท ํ•ฉ์‚ฐ PnL -14,349์› (๋ฐฑํ…Œ Optuna์™€ ์ˆซ์ž ๋‹ฌ๋ผ๋„ ์ •์ƒ โ€” ๊ณ ์ŠคํŠธยท์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑ ๊ฒฝ๋กœ ์ฐจ์ด). +- ์‚ฌํ›„ํ•ฉ๊ฒฉ 1์œ„: trial #135 ยท ๊ฑฐ๋ž˜ 469๊ฑด ยท ์Šน๋ฅ  74.4% ยท PF 3.02 ยท PnL 49,639์› +- ํ‘œ๋ณธ ์žฅ์ด 1์ผ๋ฟ์ด๋ผ, โ€˜์ด์ „ ์žฅ์— ์ž˜ ๋จนํžŒ ์ˆซ์žโ€™์ผ ๋ฟ **์ถ”์„ธ๊ฐ€ ๋ฐ”๋€Œ๋ฉด ๋ฐ”๋กœ ๊นจ์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.** + +## ์•ž์œผ๋กœ ์žฅ์—์„œ๋Š” +- **1~2์ผ Optuna best๋ฅผ ๋ฐ”๋กœ ์‹ค๋งค์— ๋„ฃ์ง€ ๋งˆ์„ธ์š”.** ๋‹ค์ผ(โ‰ฅ5๊ฑฐ๋ž˜์ผ) ์žฌ๊ฒ€์ฆยท์›น๋ฐฑํ…Œ 1ํšŒ ํ›„ ๊ฒ€ํ† . +- ์ ์šฉ ์‹œ์—๋Š” `results_gated` ํ›„๋ณด๋งŒ. ํƒ์ƒ‰์šฉ best(objective)์™€ ๋‹ค๋ฅผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. +- ์žฅ์ด ์ข์•„์ง€๊ฑฐ๋‚˜ ๋ณ€๋™์„ฑ์ด ์ปค์ง€๋ฉด: ์†์ ˆยทํŠธ๋ ˆ์ผยท์‹œ๊ฐ„์ฐฝ์ด ๋จผ์ € ๊นจ์ง‘๋‹ˆ๋‹ค. ์Šน๋ฅ  ์ž๋ž‘๋ณด๋‹ค **์†์ ˆ์ด ์‚ด์•„ ์žˆ๋Š”์ง€**๋ฅผ ๋ณด์„ธ์š”. +- ์‚ฌํ›„ํ•ฉ๊ฒฉ์ด ์žˆ์–ด๋„ โ€˜๋‚ด์ผ๋„ ๊ฐ™์€ ์žฅโ€™์ด ์•„๋‹™๋‹ˆ๋‹ค. ํŽ˜์ดํผ/์†Œ์•กยท๋ชจ์˜๋กœ 1~2์ผ ๊ด€์ฐฐ ํ›„ ํ™•๋Œ€ํ•˜์„ธ์š”. + +_์ƒ์„ฑ: 2026-09-06 13:12:24 (rule)_ + +## AI ์ฝ”๋ฉ˜ํŠธ (์ด์ „ ์žฅ / ์•ž์œผ๋กœ ์žฅ) [gemini] + +## ์ด์ „ ์žฅ์—์„œ๋Š” +์‹ค๋งค ๊ณ„์ขŒ์—์„œ๋Š” 10๊ฑด ๊ฑฐ๋ž˜๋กœ -1.4๋งŒ์› ์†์‹ค์ด ๋ฐœ์ƒํ–ˆ์œผ๋‚˜, ๋ฐฑํ…Œ์ŠคํŠธ์—์„œ๋Š” ์‚ฌํ›„ํ•ฉ๊ฒฉ 1์œ„๊ฐ€ 469๊ฑด ๊ฑฐ๋ž˜๋กœ 4.9๋งŒ์›์˜ ์ข‹์€ ์ˆ˜์ต๋ฅ ์„ ๋ณด์˜€์Šต๋‹ˆ๋‹ค. ์‹ค๋งค์™€ ๋ฐฑํ…Œ์˜ ์ด๋Ÿฌํ•œ ๊ดด๋ฆฌ๋Š” ๊ณ ์ŠคํŠธ ํผ์ง€ ๋“ฑ ์‹ค์ œ ์‹œ์žฅ ํ™˜๊ฒฝ ์ฐจ์ด๋กœ ์ •์ƒ์ด๋ฉฐ, ํŠนํžˆ ์ด๋ฒˆ ๋ฐฑํ…Œ๋Š” ๋‹จ ํ•˜๋ฃจ ๋ฐ์ดํ„ฐ์ด๋ฏ€๋กœ ๊ณผ์ ํ•ฉ ๋ฐ ํ‘œ๋ณธ ๋ถ€์กฑ ์œ„ํ—˜์ด ๋งค์šฐ ํฝ๋‹ˆ๋‹ค. ๊ณผ๊ฑฐ์˜ ์ข‹์€ ๊ฒฐ๊ณผ๊ฐ€ ๋ฏธ๋ž˜๋ฅผ ๋ณด์žฅํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. + +## ์•ž์œผ๋กœ ์žฅ์—์„œ๋Š” +๋‹จ ํ•˜๋ฃจ ๋ฐฑํ…Œ ๊ฒฐ๊ณผ๋ฅผ ์‹ค๋งค์— ์ฆ‰์‹œ ์ ์šฉํ•˜๋Š” ๊ฒƒ์€ ์œ„ํ—˜ํ•ฉ๋‹ˆ๋‹ค. ์ตœ์†Œ 5์ผ ์ด์ƒ ์žฌ๊ฒ€์ฆ๊ณผ ์›น๋ฐฑํ…Œ, ๊ทธ๋ฆฌ๊ณ  ํŽ˜์ดํผ/์†Œ์•ก ๋ชจ์˜ ํˆฌ์ž๋ฅผ ํ†ตํ•ด ํŒŒ๋ผ๋ฏธํ„ฐ์˜ ์•ˆ์ •์„ฑ์„ ๋จผ์ € ํ™•์ธํ•˜์„ธ์š”. ์‹œ์žฅ ๋ณ€ํ™” ์‹œ ๋†’์€ ์Šน๋ฅ ๋ณด๋‹ค ์†์ ˆ ์ž‘๋™ ์—ฌ๋ถ€๊ฐ€ ํ•ต์‹ฌ์ž…๋‹ˆ๋‹ค. 'mode Top10 1์œ„'๋ฅผ ์ต์ ˆ ๋Œ€ํ‘œ๋กœ ๋‹จ์ •ํ•˜์ง€ ๋งˆ์‹œ๊ณ , ์‚ฌํ›„ํ•ฉ๊ฒฉ(gated)๋œ DB 1์ˆœ์œ„๋ฅผ ๊ธฐ์ค€์œผ๋กœ ์‹ ์ค‘ํžˆ ๊ฒ€ํ†  ๋ฐ”๋ž๋‹ˆ๋‹ค. ํŠน์ • ์ข…๋ชฉ ๋งค์ˆ˜ ์ถ”์ฒœ์ด๋‚˜ ํ™•์ • ์ˆ˜์ต ์•ฝ์†์€ ๋ถˆ๊ฐ€ํ•ฉ๋‹ˆ๋‹ค. diff --git a/kis_trader/backtest/results/optuna_scalp_tpe_20260906_131534.briefing.md b/kis_trader/backtest/results/optuna_scalp_tpe_20260906_131534.briefing.md new file mode 100644 index 0000000..c05eac4 --- /dev/null +++ b/kis_trader/backtest/results/optuna_scalp_tpe_20260906_131534.briefing.md @@ -0,0 +1,71 @@ +# Optuna ๋ธŒ๋ฆฌํ•‘ โ€” ์Šค์บ˜ํ•‘ (tpe) +๊ธฐ๊ฐ„: 2026-09-04 ~ 2026-09-04 (๊ฑฐ๋ž˜์ผโ‰ˆ1์ผ) ยท trials 200/200 +ํƒ์ƒ‰ ๊ฒŒ์ดํŠธ: WRโ‰ฅ0% PFโ‰ฅ0 ยท min_tradesโ‰ฅ2 | ํ›„๋ณด ๊ฒŒ์ดํŠธ: WRโ‰ฅ40% PFโ‰ฅ1 ยท min_tradesโ‰ฅ2 +- min_trades=2: **ํ•ฉ๊ฒฉ ์ธ์ • ์ตœ์†Œ ๊ฑฐ๋ž˜ ๊ฑด์ˆ˜**(ํ‘œ๋ณธ ๋ถ€์กฑยท์šฐ์—ฐ ์Šน๋ฅ  ๋ฐฉ์ง€). ์ด๋ณด๋‹ค ์ ์€ ์กฐํ•ฉ์€ ํ•™์Šต/ํ›„๋ณด ์ง‘๊ณ„์—์„œ ์ œ์™ธ๋ฉ๋‹ˆ๋‹ค. +ํ•™์Šต์šฉ ํ†ต๊ณผ 170๊ฑด ยท ์‚ฌํ›„ํ•ฉ๊ฒฉ(results_gated) 158๊ฑด + +## ๊ณผ์ ํ•ฉยท์ ์šฉ ๊ฐ€๋Šฅ๋„ (ํœด๋ฆฌ์Šคํ‹ฑ) +- **๊ณผ์ ํ•ฉ ์œ„ํ—˜ 50.0%** ยท **์ ์šฉ ๊ฐ€๋Šฅ๋„ 50.0%** ยท ํŒ์ •: **์ฃผ์˜** โ€” ์ ์šฉ ๊ฐ€๋Šฅ๋„ ์ค‘๊ฐ„ โ€” ๋‹ค์ผ(โ‰ฅ5์ผ) ์žฌ๊ฒ€์ฆยท์›น๋ฐฑํ…Œ ํ›„ ์†Œ์•ก๋งŒ + - ํ‘œ๋ณธ ์žฅ์ผ: +40.0p โ€” ๊ฑฐ๋ž˜์ผโ‰ˆ1์ผ โ€” ๋‹จ์ผ ์žฅ ๊ณผ์ ํ•ฉ ์œ„ํ—˜ ์ตœ๋Œ€ + - ๊ฑฐ๋ž˜ ํ‘œ๋ณธ: +0.0p โ€” ์ƒ์œ„ ํ›„๋ณด ๊ฑฐ๋ž˜ 467๊ฑด โ€” ์ƒ๋Œ€์  ์–‘ํ˜ธ + - ์Šน๋ฅ ยทPF ์ด์ƒ์น˜: +0.0p โ€” ์ด์ƒ์น˜ ์—†์Œ + - ๊ฒŒ์ดํŠธ ์ปค๋ฒ„: +10.0p โ€” gated/all=158/170 โ€” ๋‹จ์ผ์— ๋Œ€๋ถ€๋ถ„ ํ†ต๊ณผ(ํ•„ํ„ฐ ๋А์Šจยท๋…ธ์ด์ฆˆ) + - PnL ๊ณ ์›: +0.0p โ€” ๊ณ ์› ๋น„์œจ 1% (1๊ฑด) +- ์ž„๊ณ„๊ฐ’ ๋ถ„ํฌ ํ‘œ๋ณธ: results_gated ์ƒ์œ„ 30๊ฑด +| ํŒŒ๋ผ๋ฏธํ„ฐ | median | p25~p75 | mode(๋น„์œจ) | +|---|---:|---|---| +| `rsi_period` | 4.0 | 4.0 ~ 5.0 | 4 (57%) | +| `rsi_oversold` | 29.0 | 27.625 ~ 30.0 | 30.0 (33%) | +| `rsi_overbought` | 77.25 | 75.0 ~ 81.75 | 77.0 (17%) | +| `sl_pct` | 5.55 | 5.3 ~ 5.8 | 5.8 (17%) | +| `tp_pct` | 1.0 | 0.8 ~ 1.7 | 1.0 (17%) | +| `tp_max_pct` | 5.75 | 3.625 ~ 8.5 | 8.5 (10%) | +| `drop_rate` | 3.3 | 2.825 ~ 7.4 | 2.7 (13%) | +| `shoulder_min_high` | 3.5 | 2.925 ~ 3.9 | 3.9 (17%) | +| `shoulder_cut_pct` | 0.35 | 0.3 ~ 0.35 | 0.35 (47%) | +| `cooldown_min` | 10.0 | 9.0 ~ 11.0 | 11 (27%) | +| `high_chase_thr` | 0.9775 | 0.97 ~ 0.99 | 0.97 (30%) | +| `max_daily_chg` | 15.0 | 12.0 ~ 17.75 | 15.0 (17%) | +- _์ฐธ๊ณ : ๊ณผ์ ํ•ฉ%๋Š” ๊ต์ฐจ๊ฒ€์ฆ ์ ์ˆ˜๊ฐ€ ์•„๋‹ˆ๋ผ ํ‘œ๋ณธยท์ด์ƒ์น˜ยท๊ณ ์› ํœด๋ฆฌ์Šคํ‹ฑ์ž…๋‹ˆ๋‹ค. ์ ์šฉ ๊ฐ€๋Šฅ๋„%=100โˆ’๊ณผ์ ํ•ฉ์œ„ํ—˜%. DB ์ ์šฉ ๋ฒ„ํŠผ ํ™œ์„ฑ ์กฐ๊ฑด(gated PnL>0)๊ณผ๋Š” ๋ณ„๊ฐœ์ž…๋‹ˆ๋‹ค._ + +## ์ตœ์ข… ์„ ํƒ ํ›„๋ณด (๊ทœ์น™ ยท DB ์ ์šฉ ์ „ ํ™•์ธ) +- ์•„๋ž˜๋Š” **์—ญํ• ์ด ๋‹ค๋ฅธ** 4์ข… ํ›„๋ณด์ž…๋‹ˆ๋‹ค. mode Top10 1์œ„ โ‰  ์ต์ ˆ ๋Œ€ํ‘œ ยท **DB 1์ˆœ์œ„๋Š” ์‚ฌํ›„ํ•ฉ๊ฒฉ(gated)** ์ž…๋‹ˆ๋‹ค. +- mode pool: `positive` ยท scoring: `band_proximity_p25_p75` + +### ํ›„๋ณด 4์ข… +- **โ‘  ์‚ฌํ›„ํ•ฉ๊ฒฉ 1์œ„ (apply: gated)** (trial #175): PnL 52,430์› ยท WR 69.0% ยท PF 2.69 ยท ๊ฑฐ๋ž˜ 467๊ฑด ยท ์•ˆ์ •์ ์ˆ˜ 2664 ยท ํ˜ธ๊ฐ€ON spr7.8 r0.70 askร—25 ยท ์ต์ ˆ1.0% ์ƒํ•œ4.5% ์†์ ˆ5.7% ยท ํœฉ์˜ON sub30s lb180s dip0.40% tol0.10% +- **โ‘ก ์•ˆ์ • 1์œ„ (apply: stable)** (trial #30): PnL 8,481์› ยท WR 89.0% ยท PF 4.40 ยท ๊ฑฐ๋ž˜ 91๊ฑด ยท ์•ˆ์ •์ ์ˆ˜ 3912 ยท ํ˜ธ๊ฐ€ON spr4.6 r0.75 askร—37 ยท ์ต์ ˆ0.5% ์ƒํ•œ8.0% ์†์ ˆ4.0% ยท ํœฉ์˜OFF +- **โ‘ข mode_combo (apply: mode)** (trial ์—†์Œ(์กฐ๋ฆฝ)): PnL 41,013์› ยท WR 74.8% ยท PF 2.61 ยท ๊ฑฐ๋ž˜ 505๊ฑด ยท ์•ˆ์ •์ ์ˆ˜ -12 ยท ํ˜ธ๊ฐ€ON spr7.9 r0.30 askร—18 ยท ์ต์ ˆ0.7% ์ƒํ•œ8.5% ์†์ ˆ5.4% ยท ํœฉ์˜OFF ยท tp ์ตœ๋นˆ 0.7% (11/158) +- **โ‘ฃ mode Top10 1์œ„ (apply: consensus ยท ๋ฐด๋“œ ์ „ํ˜• trial)** (trial #157): PnL 45,907์› ยท WR 73.5% ยท PF 2.63 ยท ๊ฑฐ๋ž˜ 555๊ฑด ยท ์•ˆ์ •์ ์ˆ˜ -337 ยท ๊ทผ์ ‘ 98.5% (28/32์ถ• ๋ฐด๋“œ์•ˆ) ยท ํ˜ธ๊ฐ€ON spr6.0 r0.70 askร—22 ยท ์ต์ ˆ0.7% ์ƒํ•œ9.0% ์†์ ˆ5.8% ยท ํœฉ์˜ON sub30s lb180s dip0.70% tol0.10% + +- mode pool tp_pct ๋ฐด๋“œ p25~p75: **0.9~2.3%** ยท Top10 1์œ„ tp=0.7% โ†’ ๋ฐด๋“œ **๋ฐ–**(๋‹ค๋ฅธ ์ถ• ๋ณด์ •์œผ๋กœ ๊ทผ์ ‘% ๋†’์Œ) +- mode Top10 meta: pool 158๊ฑด ยท ์ถ• 32๊ฐœ + +### ์ถ”์ฒœ (์ž๋™ ยท confirm ํ•„์ˆ˜) +1. **์‹ค๋งค DB ์ ์šฉ 1์ˆœ์œ„ โ†’ โ‘  ์‚ฌํ›„ํ•ฉ๊ฒฉ 1์œ„** (`optunaApply gated`) โ€” WR/PFยทmin_trades ์‚ฌํ›„ ํ†ต๊ณผ. +2. **๋ณ€๋™์„ฑยท์†์‹ค์ผ ์ค„์ด๊ธฐ โ†’ โ‘ก ์•ˆ์ • 1์œ„** (`stable`) โ€” PnL๋ณด๋‹ค ์ผ๋ณ„ ์•ˆ์ • ์šฐ์„  ์‹œ. +3. **2์ฐจ narrowยท๋Œ€ํ‘œ ์ˆซ์ž โ†’ โ‘ข mode_combo** โ€” ์ถ•๋ณ„ ์ตœ๋นˆ ์กฐ๋ฆฝ ยท trial ๋ฒˆํ˜ธ ์—†์Œ ยท ์ต์ ˆ์€ pool ์ตœ๋นˆ๊ฐ’ ์ฐธ๊ณ . +4. **โ‘ฃ mode Top10 1์œ„** โ€” ์–‘์ˆ˜ pool ์ „ํ˜• trial(๋‹ค์ถ• ๋ฐด๋“œ ๊ทผ์ ‘). **์ต์ ˆ ํ•˜๋‚˜๋กœ ์“ฐ์ง€ ๋ง ๊ฒƒ** ยท ํ‘œ์—์„œ ใ€Œ๋ณด๊ธฐใ€โ†’ consensus apply. + +## ์ด์ „ ์žฅ์—์„œ๋Š” +- ์‹ค๋งค ๋™๊ธฐ๊ฐ„ ์ฒญ์‚ฐ 10๊ฑด ยท ์Šน๋ฅ  40% ยท ํ•ฉ์‚ฐ PnL -14,349์› (๋ฐฑํ…Œ Optuna์™€ ์ˆซ์ž ๋‹ฌ๋ผ๋„ ์ •์ƒ โ€” ๊ณ ์ŠคํŠธยท์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑ ๊ฒฝ๋กœ ์ฐจ์ด). +- ์‚ฌํ›„ํ•ฉ๊ฒฉ 1์œ„: trial #175 ยท ๊ฑฐ๋ž˜ 467๊ฑด ยท ์Šน๋ฅ  69.0% ยท PF 2.69 ยท PnL 52,430์› +- ํ‘œ๋ณธ ์žฅ์ด 1์ผ๋ฟ์ด๋ผ, โ€˜์ด์ „ ์žฅ์— ์ž˜ ๋จนํžŒ ์ˆซ์žโ€™์ผ ๋ฟ **์ถ”์„ธ๊ฐ€ ๋ฐ”๋€Œ๋ฉด ๋ฐ”๋กœ ๊นจ์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.** + +## ์•ž์œผ๋กœ ์žฅ์—์„œ๋Š” +- **1~2์ผ Optuna best๋ฅผ ๋ฐ”๋กœ ์‹ค๋งค์— ๋„ฃ์ง€ ๋งˆ์„ธ์š”.** ๋‹ค์ผ(โ‰ฅ5๊ฑฐ๋ž˜์ผ) ์žฌ๊ฒ€์ฆยท์›น๋ฐฑํ…Œ 1ํšŒ ํ›„ ๊ฒ€ํ† . +- ์ ์šฉ ์‹œ์—๋Š” `results_gated` ํ›„๋ณด๋งŒ. ํƒ์ƒ‰์šฉ best(objective)์™€ ๋‹ค๋ฅผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. +- ์žฅ์ด ์ข์•„์ง€๊ฑฐ๋‚˜ ๋ณ€๋™์„ฑ์ด ์ปค์ง€๋ฉด: ์†์ ˆยทํŠธ๋ ˆ์ผยท์‹œ๊ฐ„์ฐฝ์ด ๋จผ์ € ๊นจ์ง‘๋‹ˆ๋‹ค. ์Šน๋ฅ  ์ž๋ž‘๋ณด๋‹ค **์†์ ˆ์ด ์‚ด์•„ ์žˆ๋Š”์ง€**๋ฅผ ๋ณด์„ธ์š”. +- ์‚ฌํ›„ํ•ฉ๊ฒฉ์ด ์žˆ์–ด๋„ โ€˜๋‚ด์ผ๋„ ๊ฐ™์€ ์žฅโ€™์ด ์•„๋‹™๋‹ˆ๋‹ค. ํŽ˜์ดํผ/์†Œ์•กยท๋ชจ์˜๋กœ 1~2์ผ ๊ด€์ฐฐ ํ›„ ํ™•๋Œ€ํ•˜์„ธ์š”. + +_์ƒ์„ฑ: 2026-09-06 13:15:35 (rule)_ + +## AI ์ฝ”๋ฉ˜ํŠธ (์ด์ „ ์žฅ / ์•ž์œผ๋กœ ์žฅ) [gemini] + +## ์ด์ „ ์žฅ์—์„œ๋Š” + +๋ฐฑํ…Œ์ŠคํŠธ ๊ฒฐ๊ณผ, ์‚ฌํ›„ํ•ฉ๊ฒฉ 1์œ„(trial #175)๋Š” 1์ผ๊ฐ„ ๊ฑฐ๋ž˜ 467๊ฑด, ์Šน๋ฅ  69.0%๋กœ PnL 52,430์›์„ ๊ธฐ๋กํ–ˆ์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์‹ค์ œ ๋งค๋งค์—์„œ๋Š” ๋™๊ธฐ๊ฐ„ -14,349์›์˜ ์†์‹ค์ด ๋ฐœ์ƒํ•˜์—ฌ, ๋ฐฑํ…Œ์ŠคํŠธ์™€ ์‹ค๋งค ๊ฐ„ ์ƒ๋‹นํ•œ ๊ดด๋ฆฌ(๊ณ ์ŠคํŠธยท์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑ ๊ฒฝ๋กœ ์ฐจ์ด)๊ฐ€ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š” ๋‹จ ํ•˜๋ฃจ์น˜ ๋ฐ์ดํ„ฐ๋กœ ์ตœ์ ํ™”๋ฅผ ์ง„ํ–‰ํ–ˆ๊ธฐ์—, ํŠน์ • ์‹œ์žฅ ์ƒํ™ฉ์— ๊ณผ์ ํ•ฉ๋˜์—ˆ์„ ์œ„ํ—˜์ด ๋งค์šฐ ๋†’๋‹ค๋Š” ๊ฐ•๋ ฅํ•œ ๊ฒฝ๊ณ ์ž…๋‹ˆ๋‹ค. ์ด์ „ ์žฅ์— ์ž ๊น ์ž˜ ๋งž์•˜๋˜ ์ˆซ์ž์ผ ๋ฟ, ์‹œ์žฅ ์ถ”์„ธ๊ฐ€ ๋ฐ”๋€Œ๋ฉด ์ด ๊ฒฐ๊ณผ๋Š” ์‰ฝ๊ฒŒ ๋ฌด๋„ˆ์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. + +## ์•ž์œผ๋กœ ์žฅ์—์„œ๋Š” + +๋‹จ์ผ ์žฅ์ผ ๋ฐฑํ…Œ์ŠคํŠธ ๊ฒฐ๊ณผ๋Š” ๊ณผ์ ํ•ฉ ์œ„ํ—˜ 50.0%๋กœ โ€˜์ฃผ์˜โ€™ ํŒ์ •์„ ๋ฐ›์•˜์Šต๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ์ด๋ฒˆ 1~2์ผ์น˜ Optuna ์ตœ์ ๊ฐ’์„ ์‹ค๋งค์— ๋ฐ”๋กœ ์ ์šฉํ•˜๋Š” ๊ฒƒ์€ ๋งค์šฐ ์œ„ํ—˜ํ•ฉ๋‹ˆ๋‹ค. ์ตœ์†Œ 5์ผ ์ด์ƒ์˜ ๋‹ค์ผ ์žฌ๊ฒ€์ฆ๊ณผ ์›น๋ฐฑํ…Œ์ŠคํŠธ๋ฅผ ๊ฑฐ์นœ ํ›„ ์†Œ์•ก ๋ชจ์˜ ๋˜๋Š” ํŽ˜์ดํผ ํŠธ๋ ˆ์ด๋”ฉ์œผ๋กœ ๊ด€์ฐฐํ•˜๋ฉฐ ์‹ ์ค‘ํ•˜๊ฒŒ ์ ‘๊ทผํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ํŠนํžˆ, `mode Top10 1์œ„`๋Š” ์ต์ ˆ ๋Œ€ํ‘œ๊ฐ€ ์•„๋‹ˆ๋ฉฐ, ์šฐ๋ฆฌ ์‹œ์Šคํ…œ์˜ ์•ˆ์ •์ ์ธ ๋งค๋งค๋ฅผ ์œ„ํ•ด์„œ๋Š” `results_gated` ํ›„๋ณด๋“ค ์ค‘ ์„ ํƒํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์‹ค๋งค์™€ ๋ฐฑํ…Œ์ŠคํŠธ์˜ ๊ดด๋ฆฌ, ์ฆ‰ '๋‚ด์ผ๋„ ๊ฐ™์€ ์žฅ'์ด ์•„๋‹˜์„ ํ•ญ์ƒ ์ธ์ง€ํ•˜๊ณ , ๋†’์€ ์Šน๋ฅ ๋ณด๋‹ค ์†์ ˆ์ด ์ œ๋Œ€๋กœ ์ž‘๋™ํ•˜๋Š”์ง€ ์ ๊ฒ€ํ•˜๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค. diff --git a/kis_trader/backtest/results/optuna_tail_fast_20260903_135221.briefing.md b/kis_trader/backtest/results/optuna_tail_fast_20260903_135221.briefing.md new file mode 100644 index 0000000..2feda7f --- /dev/null +++ b/kis_trader/backtest/results/optuna_tail_fast_20260903_135221.briefing.md @@ -0,0 +1,51 @@ +# Optuna ๋ธŒ๋ฆฌํ•‘ โ€” ๊ผฌ๋ฆฌ (fast) +๊ธฐ๊ฐ„: 2026-08-30 ~ 2026-08-31 (๊ฑฐ๋ž˜์ผโ‰ˆ2์ผ) ยท trials 5/5 +ํƒ์ƒ‰ ๊ฒŒ์ดํŠธ: WRโ‰ฅ0% PFโ‰ฅ0 ยท min_tradesโ‰ฅ1 | ํ›„๋ณด ๊ฒŒ์ดํŠธ: WRโ‰ฅ40% PFโ‰ฅ1 ยท min_tradesโ‰ฅ1 +- min_trades=1: **ํ•ฉ๊ฒฉ ์ธ์ • ์ตœ์†Œ ๊ฑฐ๋ž˜ ๊ฑด์ˆ˜**(ํ‘œ๋ณธ ๋ถ€์กฑยท์šฐ์—ฐ ์Šน๋ฅ  ๋ฐฉ์ง€). ์ด๋ณด๋‹ค ์ ์€ ์กฐํ•ฉ์€ ํ•™์Šต/ํ›„๋ณด ์ง‘๊ณ„์—์„œ ์ œ์™ธ๋ฉ๋‹ˆ๋‹ค. +ํ•™์Šต์šฉ ํ†ต๊ณผ 0๊ฑด ยท ์‚ฌํ›„ํ•ฉ๊ฒฉ(results_gated) 0๊ฑด + +## ๊ณผ์ ํ•ฉยท์ ์šฉ ๊ฐ€๋Šฅ๋„ (ํœด๋ฆฌ์Šคํ‹ฑ) +- **๊ณผ์ ํ•ฉ ์œ„ํ—˜ 61.0%** ยท **์ ์šฉ ๊ฐ€๋Šฅ๋„ 39.0%** ยท ํŒ์ •: **์ฃผ์˜** โ€” ์ ์šฉ ๊ฐ€๋Šฅ๋„ ์ค‘๊ฐ„ โ€” ๋‹ค์ผ(โ‰ฅ5์ผ) ์žฌ๊ฒ€์ฆยท์›น๋ฐฑํ…Œ ํ›„ ์†Œ์•ก๋งŒ + - ํ‘œ๋ณธ ์žฅ์ผ: +28.0p โ€” ๊ฑฐ๋ž˜์ผโ‰ˆ2์ผ โ€” ์ดํ‹€๋งŒ์œผ๋กœ๋Š” ์ถ”์„ธ ์ „ํ™˜์— ์ทจ์•ฝ + - ๊ฑฐ๋ž˜ ํ‘œ๋ณธ: +25.0p โ€” ํ†ต๊ณผ ํ›„๋ณด ์—†์Œ โ€” ์ ์šฉ ๋ถˆ๊ฐ€ + - ์Šน๋ฅ ยทPF ์ด์ƒ์น˜: +0.0p โ€” ์ด์ƒ์น˜ ์—†์Œ + - ๊ฒŒ์ดํŠธ ์ปค๋ฒ„: +8.0p โ€” ํ•™์Šตยทgated ๋ชจ๋‘ ๋น„์–ด ์žˆ์Œ + - PnL ๊ณ ์›: +0.0p โ€” ๊ณ ์› ํŒ์ • ์Šคํ‚ต +- _์ฐธ๊ณ : ๊ณผ์ ํ•ฉ%๋Š” ๊ต์ฐจ๊ฒ€์ฆ ์ ์ˆ˜๊ฐ€ ์•„๋‹ˆ๋ผ ํ‘œ๋ณธยท์ด์ƒ์น˜ยท๊ณ ์› ํœด๋ฆฌ์Šคํ‹ฑ์ž…๋‹ˆ๋‹ค. ์ ์šฉ ๊ฐ€๋Šฅ๋„%=100โˆ’๊ณผ์ ํ•ฉ์œ„ํ—˜%. DB ์ ์šฉ ๋ฒ„ํŠผ ํ™œ์„ฑ ์กฐ๊ฑด(gated PnL>0)๊ณผ๋Š” ๋ณ„๊ฐœ์ž…๋‹ˆ๋‹ค._ + +## ์ตœ์ข… ์„ ํƒ ํ›„๋ณด (๊ทœ์น™ ยท DB ์ ์šฉ ์ „ ํ™•์ธ) +- ์•„๋ž˜๋Š” **์—ญํ• ์ด ๋‹ค๋ฅธ** 4์ข… ํ›„๋ณด์ž…๋‹ˆ๋‹ค. mode Top10 1์œ„ โ‰  ์ต์ ˆ ๋Œ€ํ‘œ ยท **DB 1์ˆœ์œ„๋Š” ์‚ฌํ›„ํ•ฉ๊ฒฉ(gated)** ์ž…๋‹ˆ๋‹ค. +- mode pool: `positive` ยท scoring: `band_proximity_p25_p75` + +### ํ›„๋ณด 4์ข… +- **โ‘  ์‚ฌํ›„ํ•ฉ๊ฒฉ 1์œ„ (apply: gated)**: ์—†์Œ +- **โ‘ก ์•ˆ์ • 1์œ„ (apply: stable)**: ์—†์Œ +- **โ‘ข mode_combo (apply: mode)**: ์—†์Œ (๋ฏธ์‚ฐ์ถœยท๊ตฌ JSON) +- **โ‘ฃ mode Top10 1์œ„ (apply: consensus ยท ๋ฐด๋“œ ์ „ํ˜• trial)**: ์—†์Œ +- mode Top10 meta: pool 0๊ฑด ยท ์ถ• 0๊ฐœ + +### ์ถ”์ฒœ (์ž๋™ ยท confirm ํ•„์ˆ˜) +1. **์‚ฌํ›„ํ•ฉ๊ฒฉ 0๊ฑด โ†’ DB ์ ์šฉ ๋น„๊ถŒ์žฅ.** ํ˜„ํ–‰ DB ์œ ์ง€ + ์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑยท๊ธฐ๊ฐ„ ์žฌ๊ฒ€์ฆ. +- โš  ์•ˆ์ • ๊ฒŒ์ดํŠธ 0๊ฑด โ†’ ์•ˆ์ • Top์€ **์ ์ˆ˜์ˆœ ํด๋ฐฑ** (์•ˆ์ • ๊ฒŒ์ดํŠธ 0๊ฑด โ†’ ํ•™์Šตํ’€ ์•ˆ์ •์ ์ˆ˜์ˆœ TopN (๋งˆ์ด๋„ˆ์Šค PnL ํฌํ•จ ยท ์ƒ๋Œ€๋น„๊ต)) + +## ์ด์ „ ์žฅ์—์„œ๋Š” +- ์‹ค๋งค ๋™๊ธฐ๊ฐ„ ์ฒญ์‚ฐ 1๊ฑด ยท ์Šน๋ฅ  100% ยท ํ•ฉ์‚ฐ PnL 1,854์› (๋ฐฑํ…Œ Optuna์™€ ์ˆซ์ž ๋‹ฌ๋ผ๋„ ์ •์ƒ โ€” ๊ณ ์ŠคํŠธยท์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑ ๊ฒฝ๋กœ ์ฐจ์ด). +- ์ด ๊ธฐ๊ฐ„ ๋ฐฑํ…Œ์—์„œ๋Š” **์œ ์˜๋ฏธํ•œ ํ†ต๊ณผ ์กฐํ•ฉ์ด ๊ฑฐ์˜ ์—†์—ˆ์Šต๋‹ˆ๋‹ค.** ์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑยท์†์ ˆยท์‹œ๊ฐ„์ฐฝ์„ ๋จผ์ € ์ ๊ฒ€ํ•˜์„ธ์š” (๋ŒํŒŒ 0๊ฑด์ด๋ฉด ํŠนํžˆ). + +## ์•ž์œผ๋กœ ์žฅ์—์„œ๋Š” +- **1~2์ผ Optuna best๋ฅผ ๋ฐ”๋กœ ์‹ค๋งค์— ๋„ฃ์ง€ ๋งˆ์„ธ์š”.** ๋‹ค์ผ(โ‰ฅ5๊ฑฐ๋ž˜์ผ) ์žฌ๊ฒ€์ฆยท์›น๋ฐฑํ…Œ 1ํšŒ ํ›„ ๊ฒ€ํ† . +- ์ ์šฉ ์‹œ์—๋Š” `results_gated` ํ›„๋ณด๋งŒ. ํƒ์ƒ‰์šฉ best(objective)์™€ ๋‹ค๋ฅผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. +- ์žฅ์ด ์ข์•„์ง€๊ฑฐ๋‚˜ ๋ณ€๋™์„ฑ์ด ์ปค์ง€๋ฉด: ์†์ ˆยทํŠธ๋ ˆ์ผยท์‹œ๊ฐ„์ฐฝ์ด ๋จผ์ € ๊นจ์ง‘๋‹ˆ๋‹ค. ์Šน๋ฅ  ์ž๋ž‘๋ณด๋‹ค **์†์ ˆ์ด ์‚ด์•„ ์žˆ๋Š”์ง€**๋ฅผ ๋ณด์„ธ์š”. +- ํ˜„์žฌ ์‚ฌํ›„ํ•ฉ๊ฒฉ 0๊ฑด โ†’ ํŒŒ๋ผ๋ฏธํ„ฐ ์œ ์ง€(ํ˜„ํ–‰ DB) + ์œ ๋‹ˆ๋ฒ„์Šค/๋ฐ์ดํ„ฐ ์ ๊ฒ€์ด ์šฐ์„ ์ž…๋‹ˆ๋‹ค. + +_์ƒ์„ฑ: 2026-09-03 13:52:22 (rule)_ + +## AI ์ฝ”๋ฉ˜ํŠธ (์ด์ „ ์žฅ / ์•ž์œผ๋กœ ์žฅ) [gemini] + +## ์ด์ „ ์žฅ์—์„œ๋Š” + +์ด์ „ ์‹ค๋งค์—์„œ๋Š” 1๊ฑด ์ฒญ์‚ฐ์œผ๋กœ 1,854์›์˜ ์ˆ˜์ต์„ ๊ธฐ๋กํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š” ๋ฐฑํ…Œ์ŠคํŠธ์™€ ์œ ๋‹ˆ๋ฒ„์Šค, ํ‹ฑ ๋“ฑ ๊ฒฝ๋กœ ์ฐจ์ด๋กœ ์ •์ƒ์ž…๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋ฐฑํ…Œ์ŠคํŠธ Optuna ๊ฒฐ๊ณผ๋Š” 2๊ฑฐ๋ž˜์ผ์ด๋ผ๋Š” ์งง์€ ๊ธฐ๊ฐ„ ํƒ“์— ์‚ฌํ›„ํ•ฉ๊ฒฉ ๋“ฑ ์œ ์˜๋ฏธํ•œ ํ†ต๊ณผ ์กฐํ•ฉ์ด ์ „๋ฌดํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ณผ์ ํ•ฉ ์œ„ํ—˜ 61%, ์ ์šฉ ๊ฐ€๋Šฅ๋„ 39%๋กœ '์ฃผ์˜' ํŒ์ •์ด ๋‚˜์™”์Šต๋‹ˆ๋‹ค. + +## ์•ž์œผ๋กœ ์žฅ์—์„œ๋Š” + +**์ด 2์ผ๊ฐ„์˜ Optuna ๊ฒฐ๊ณผ๋ฅผ ์‹ค๋งค์— ์ง์ ‘ ์ ์šฉํ•˜๋Š” ๊ฒƒ์€ ๊ณผ์ ํ•ฉ ์œ„ํ—˜์ด ๋งค์šฐ ๋†’์•„ ์ ˆ๋Œ€ ๊ธˆ์ง€ํ•ฉ๋‹ˆ๋‹ค.** ํ˜„์žฌ DB 1์ˆœ์œ„์ธ '์‚ฌํ›„ํ•ฉ๊ฒฉ 1์œ„' ํ›„๋ณด๊ฐ€ ์—†์œผ๋ฏ€๋กœ ์‹ ๊ทœ ์ „๋žต ์ ์šฉ์€ ๋ถˆ๊ฐ€ํ•˜๋ฉฐ, ํ˜„ํ–‰ DB ์ „๋žต์„ ์œ ์ง€ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ตœ์†Œ 5๊ฑฐ๋ž˜์ผ ์ด์ƒ์œผ๋กœ ๊ธฐ๊ฐ„์„ ๋Š˜๋ ค ์žฌ๊ฒ€์ฆํ•˜๊ณ , ์›น๋ฐฑํ…Œ์ŠคํŠธ๋ฅผ ํ†ตํ•ด ์‹ค๋งค์™€์˜ ๊ดด๋ฆฌ(๊ณ ์ŠคํŠธํผ์ง€ ๋“ฑ)๋ฅผ ๋ฉด๋ฐ€ํžˆ ์ ๊ฒ€ ํ›„ ์†Œ์•ก ์ ์šฉ์„ ๊ณ ๋ คํ•˜์‹ญ์‹œ์˜ค. ์Šน๋ฅ ๋ณด๋‹ค ์†์ ˆ ๊ธฐ๋Šฅ์ด ์‚ด์•„์žˆ๋Š”์ง€ ํ™•์ธํ•˜๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค. diff --git a/kis_trader/backtest/results/optuna_tail_fast_20260903_135553.briefing.md b/kis_trader/backtest/results/optuna_tail_fast_20260903_135553.briefing.md new file mode 100644 index 0000000..a25c288 --- /dev/null +++ b/kis_trader/backtest/results/optuna_tail_fast_20260903_135553.briefing.md @@ -0,0 +1,71 @@ +# Optuna ๋ธŒ๋ฆฌํ•‘ โ€” ๊ผฌ๋ฆฌ (fast) +๊ธฐ๊ฐ„: 2026-08-30 ~ 2026-08-31 (๊ฑฐ๋ž˜์ผโ‰ˆ2์ผ) ยท trials 5/5 +ํƒ์ƒ‰ ๊ฒŒ์ดํŠธ: WRโ‰ฅ0% PFโ‰ฅ0 ยท min_tradesโ‰ฅ1 | ํ›„๋ณด ๊ฒŒ์ดํŠธ: WRโ‰ฅ40% PFโ‰ฅ1 ยท min_tradesโ‰ฅ1 +- min_trades=1: **ํ•ฉ๊ฒฉ ์ธ์ • ์ตœ์†Œ ๊ฑฐ๋ž˜ ๊ฑด์ˆ˜**(ํ‘œ๋ณธ ๋ถ€์กฑยท์šฐ์—ฐ ์Šน๋ฅ  ๋ฐฉ์ง€). ์ด๋ณด๋‹ค ์ ์€ ์กฐํ•ฉ์€ ํ•™์Šต/ํ›„๋ณด ์ง‘๊ณ„์—์„œ ์ œ์™ธ๋ฉ๋‹ˆ๋‹ค. +ํ•™์Šต์šฉ ํ†ต๊ณผ 5๊ฑด ยท ์‚ฌํ›„ํ•ฉ๊ฒฉ(results_gated) 0๊ฑด + +## ๊ณผ์ ํ•ฉยท์ ์šฉ ๊ฐ€๋Šฅ๋„ (ํœด๋ฆฌ์Šคํ‹ฑ) +- **๊ณผ์ ํ•ฉ ์œ„ํ—˜ 62.0%** ยท **์ ์šฉ ๊ฐ€๋Šฅ๋„ 38.0%** ยท ํŒ์ •: **์ฃผ์˜** โ€” ์ ์šฉ ๊ฐ€๋Šฅ๋„ ์ค‘๊ฐ„ โ€” ๋‹ค์ผ(โ‰ฅ5์ผ) ์žฌ๊ฒ€์ฆยท์›น๋ฐฑํ…Œ ํ›„ ์†Œ์•ก๋งŒ + - ํ‘œ๋ณธ ์žฅ์ผ: +28.0p โ€” ๊ฑฐ๋ž˜์ผโ‰ˆ2์ผ โ€” ์ดํ‹€๋งŒ์œผ๋กœ๋Š” ์ถ”์„ธ ์ „ํ™˜์— ์ทจ์•ฝ + - ๊ฑฐ๋ž˜ ํ‘œ๋ณธ: +10.0p โ€” ์ƒ์œ„ ํ›„๋ณด ๊ฑฐ๋ž˜ 6๊ฑด โ€” ํ•ด์„ ์‹œ ์ฃผ์˜ + - ์Šน๋ฅ ยทPF ์ด์ƒ์น˜: +0.0p โ€” ์ด์ƒ์น˜ ์—†์Œ + - ๊ฒŒ์ดํŠธ ์ปค๋ฒ„: +12.0p โ€” ์‚ฌํ›„ํ•ฉ๊ฒฉ 0๊ฑด (ํ•™์Šต 5) โ€” DB ์ ์šฉ ๋น„๊ถŒ์žฅ + - PnL ๊ณ ์›: +12.0p โ€” ๋™์ผ PnLโ‰ˆ-373์›์ด ํ›„๋ณด 5/5 (100%) โ€” ํŒŒ๋ผ๋ฏธํ„ฐ ๋ฏผ๊ฐ๋„ ๋‚ฎ์Œ/๊ณ ์› +- ์ž„๊ณ„๊ฐ’ ๋ถ„ํฌ ํ‘œ๋ณธ: results(learning) ์ƒ์œ„ 5๊ฑด +| ํŒŒ๋ผ๋ฏธํ„ฐ | median | p25~p75 | mode(๋น„์œจ) | +|---|---:|---|---| +| `entry_mode` | โ€” | โ€” | align (100%) | +| `cand_limit` | 20.0 | 0.0 ~ 20.0 | 20 (60%) | +| `max_daily_change` | 30.0 | 30.0 ~ 30.0 | 30.0 (80%) | +| `min_drop_rate` | 0.03 | 0.03 ~ 0.03 | 0.03 (80%) | +| `min_recovery_ratio` | 0.25 | 0.1 ~ 0.25 | 0.25 (60%) | +| `tail_ratio_min` | 0.6 | 0.6 ~ 1.0 | 0.6 (60%) | +| `tail_pct_min` | 0.005 | 0.001 ~ 0.005 | 0.005 (60%) | +| `max_rec_3m` | 0.85 | 0.85 ~ 0.85 | 0.85 (80%) | +| `shoulder_min_high` | 0.005 | 0.005 ~ 0.005 | 0.005 (80%) | +| `shoulder_cut_pct` | 0.002 | 0.001 ~ 0.002 | 0.002 (60%) | +| `stop_atr_mult` | 1.5 | 1.5 ~ 2.0 | 2.0 (40%) | +| `target_atr_mult` | 1.5 | 1.0 ~ 2.5 | 1.0 (40%) | +- _์ฐธ๊ณ : ๊ณผ์ ํ•ฉ%๋Š” ๊ต์ฐจ๊ฒ€์ฆ ์ ์ˆ˜๊ฐ€ ์•„๋‹ˆ๋ผ ํ‘œ๋ณธยท์ด์ƒ์น˜ยท๊ณ ์› ํœด๋ฆฌ์Šคํ‹ฑ์ž…๋‹ˆ๋‹ค. ์ ์šฉ ๊ฐ€๋Šฅ๋„%=100โˆ’๊ณผ์ ํ•ฉ์œ„ํ—˜%. DB ์ ์šฉ ๋ฒ„ํŠผ ํ™œ์„ฑ ์กฐ๊ฑด(gated PnL>0)๊ณผ๋Š” ๋ณ„๊ฐœ์ž…๋‹ˆ๋‹ค._ + +## ์ตœ์ข… ์„ ํƒ ํ›„๋ณด (๊ทœ์น™ ยท DB ์ ์šฉ ์ „ ํ™•์ธ) +- ์•„๋ž˜๋Š” **์—ญํ• ์ด ๋‹ค๋ฅธ** 4์ข… ํ›„๋ณด์ž…๋‹ˆ๋‹ค. mode Top10 1์œ„ โ‰  ์ต์ ˆ ๋Œ€ํ‘œ ยท **DB 1์ˆœ์œ„๋Š” ์‚ฌํ›„ํ•ฉ๊ฒฉ(gated)** ์ž…๋‹ˆ๋‹ค. +- mode pool: `positive` ยท scoring: `band_proximity_p25_p75` + +### ํ›„๋ณด 4์ข… +- **โ‘  ์‚ฌํ›„ํ•ฉ๊ฒฉ 1์œ„ (apply: gated)**: ์—†์Œ +- **โ‘ก ์•ˆ์ • 1์œ„ (apply: stable)** (trial #0): PnL -373์› ยท WR 50.0% ยท PF 0.15 ยท ๊ฑฐ๋ž˜ 6๊ฑด ยท ์•ˆ์ •์ ์ˆ˜ -298 ยท โ€” +- **โ‘ข mode_combo (apply: mode)** (trial ์—†์Œ(์กฐ๋ฆฝ)): PnL 0์› ยท WR 0.0% ยท PF 0.00 ยท ๊ฑฐ๋ž˜ 0๊ฑด ยท โ€” +- **โ‘ฃ mode Top10 1์œ„ (apply: consensus ยท ๋ฐด๋“œ ์ „ํ˜• trial)** (trial #3): PnL -373์› ยท WR 50.0% ยท PF 0.15 ยท ๊ฑฐ๋ž˜ 6๊ฑด ยท ์•ˆ์ •์ ์ˆ˜ -298 ยท ๊ทผ์ ‘ 95.9% (33/35์ถ• ๋ฐด๋“œ์•ˆ) ยท โ€” +- mode Top10 meta: pool 5๊ฑด ยท ์ถ• 35๊ฐœ + +### ์ถ”์ฒœ (์ž๋™ ยท confirm ํ•„์ˆ˜) +1. **์‚ฌํ›„ํ•ฉ๊ฒฉ 0๊ฑด โ†’ DB ์ ์šฉ ๋น„๊ถŒ์žฅ.** ํ˜„ํ–‰ DB ์œ ์ง€ + ์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑยท๊ธฐ๊ฐ„ ์žฌ๊ฒ€์ฆ. +2. ์ฐธ๊ณ ๋งŒ: ํ•™์Šต 1์œ„๋Š” objective ์ตœ๋Œ€์ผ ๋ฟ ์‚ฌํ›„ ๊ฒŒ์ดํŠธ ๋ฏธํ†ต๊ณผ์ผ ์ˆ˜ ์žˆ์Œ. +2. **2์ฐจ narrowยท๋Œ€ํ‘œ ์ˆซ์ž โ†’ โ‘ข mode_combo** โ€” ์ถ•๋ณ„ ์ตœ๋นˆ ์กฐ๋ฆฝ ยท trial ๋ฒˆํ˜ธ ์—†์Œ ยท ์ต์ ˆ์€ pool ์ตœ๋นˆ๊ฐ’ ์ฐธ๊ณ . +3. **โ‘ฃ mode Top10 1์œ„** โ€” ์–‘์ˆ˜ pool ์ „ํ˜• trial(๋‹ค์ถ• ๋ฐด๋“œ ๊ทผ์ ‘). **์ต์ ˆ ํ•˜๋‚˜๋กœ ์“ฐ์ง€ ๋ง ๊ฒƒ** ยท ํ‘œ์—์„œ ใ€Œ๋ณด๊ธฐใ€โ†’ consensus apply. +- โš  ์•ˆ์ • ๊ฒŒ์ดํŠธ 0๊ฑด โ†’ ์•ˆ์ • Top์€ **์ ์ˆ˜์ˆœ ํด๋ฐฑ** (์•ˆ์ • ๊ฒŒ์ดํŠธ 0๊ฑด โ†’ ํ•™์Šตํ’€ ์•ˆ์ •์ ์ˆ˜์ˆœ TopN (๋งˆ์ด๋„ˆ์Šค PnL ํฌํ•จ ยท ์ƒ๋Œ€๋น„๊ต)) + +## ์ด์ „ ์žฅ์—์„œ๋Š” +- ์‹ค๋งค ๋™๊ธฐ๊ฐ„ ์ฒญ์‚ฐ 1๊ฑด ยท ์Šน๋ฅ  100% ยท ํ•ฉ์‚ฐ PnL 1,854์› (๋ฐฑํ…Œ Optuna์™€ ์ˆซ์ž ๋‹ฌ๋ผ๋„ ์ •์ƒ โ€” ๊ณ ์ŠคํŠธยท์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑ ๊ฒฝ๋กœ ์ฐจ์ด). +- ํ•™์Šต 1์œ„(์‚ฌํ›„๊ฒŒ์ดํŠธ ๋ฏธ๋‹ฌ ๊ฐ€๋Šฅ): trial #0 ยท ๊ฑฐ๋ž˜ 6๊ฑด ยท ์Šน๋ฅ  50.0% ยท PF 0.15 ยท PnL -373์› +- ํ‘œ๋ณธ ์žฅ์ด 2์ผ๋ฟ์ด๋ผ, โ€˜์ด์ „ ์žฅ์— ์ž˜ ๋จนํžŒ ์ˆซ์žโ€™์ผ ๋ฟ **์ถ”์„ธ๊ฐ€ ๋ฐ”๋€Œ๋ฉด ๋ฐ”๋กœ ๊นจ์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.** +- ํ”Œ๋Ÿฌ์Šค/ํ•™์Šต ํ›„๋ณด๋Š” ์žˆ์œผ๋‚˜ ์Šน๋ฅ ยทPF ์‚ฌํ›„ ๊ธฐ์ค€์€ ๋ชป ๋„˜๊น€ โ†’ **๋‹น์žฅ DB ์ ์šฉ์€ ๋น„๊ถŒ์žฅ.** + +## ์•ž์œผ๋กœ ์žฅ์—์„œ๋Š” +- **1~2์ผ Optuna best๋ฅผ ๋ฐ”๋กœ ์‹ค๋งค์— ๋„ฃ์ง€ ๋งˆ์„ธ์š”.** ๋‹ค์ผ(โ‰ฅ5๊ฑฐ๋ž˜์ผ) ์žฌ๊ฒ€์ฆยท์›น๋ฐฑํ…Œ 1ํšŒ ํ›„ ๊ฒ€ํ† . +- ์ ์šฉ ์‹œ์—๋Š” `results_gated` ํ›„๋ณด๋งŒ. ํƒ์ƒ‰์šฉ best(objective)์™€ ๋‹ค๋ฅผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. +- ์žฅ์ด ์ข์•„์ง€๊ฑฐ๋‚˜ ๋ณ€๋™์„ฑ์ด ์ปค์ง€๋ฉด: ์†์ ˆยทํŠธ๋ ˆ์ผยท์‹œ๊ฐ„์ฐฝ์ด ๋จผ์ € ๊นจ์ง‘๋‹ˆ๋‹ค. ์Šน๋ฅ  ์ž๋ž‘๋ณด๋‹ค **์†์ ˆ์ด ์‚ด์•„ ์žˆ๋Š”์ง€**๋ฅผ ๋ณด์„ธ์š”. +- ํ˜„์žฌ ์‚ฌํ›„ํ•ฉ๊ฒฉ 0๊ฑด โ†’ ํŒŒ๋ผ๋ฏธํ„ฐ ์œ ์ง€(ํ˜„ํ–‰ DB) + ์œ ๋‹ˆ๋ฒ„์Šค/๋ฐ์ดํ„ฐ ์ ๊ฒ€์ด ์šฐ์„ ์ž…๋‹ˆ๋‹ค. + +_์ƒ์„ฑ: 2026-09-03 13:55:56 (rule)_ + +## AI ์ฝ”๋ฉ˜ํŠธ (์ด์ „ ์žฅ / ์•ž์œผ๋กœ ์žฅ) [gemini] + +## ์ด์ „ ์žฅ์—์„œ๋Š” + +์ด์ „ ๋ฐฑํ…Œ์ŠคํŠธ๋Š” ๋‹จ 2๊ฑฐ๋ž˜์ผ์ด๋ผ๋Š” ๋งค์šฐ ์งง์€ ๊ธฐ๊ฐ„์— 5๋ฒˆ์˜ ํ•™์Šต ์‹œ๋„๋งŒ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. ํ•™์Šต ๊ฒฐ๊ณผ ์ค‘ ์ตœ์ข… ์‚ฌํ›„ํ•ฉ๊ฒฉ ๊ธฐ์ค€์„ ํ†ต๊ณผํ•œ ์กฐํ•ฉ์€ ์—†์—ˆ์œผ๋ฉฐ, ์ƒ์œ„ ํ›„๋ณด๋“ค ๋ชจ๋‘ ์†์‹ค(-373์›)์„ ๊ธฐ๋กํ–ˆ์Šต๋‹ˆ๋‹ค. ์‹ค๋งค์™€ ๋ฐฑํ…Œ์ŠคํŠธ PnL ์ฐจ์ด๋Š” ์ž์—ฐ์Šค๋Ÿฝ์ง€๋งŒ, ์ด์ฒ˜๋Ÿผ ํ‘œ๋ณธ์ด ๋ถ€์กฑํ•˜๊ณ  ๊ณผ์ ํ•ฉ ์œ„ํ—˜(62.0%)์ด ๋†’์€ ๊ฒฐ๊ณผ๋Š” **๋‹จ์ˆœํžˆ ์ด์ „ ์žฅ์—์„œ ์ž˜ ๋จนํ˜”์„ ๋ฟ, ์ถ”์„ธ ์ „ํ™˜์— ๋งค์šฐ ์ทจ์•ฝ**ํ•จ์„ ๊ฒฝ๊ณ ํ•ฉ๋‹ˆ๋‹ค. + +## ์•ž์œผ๋กœ ์žฅ์—์„œ๋Š” + +์•ž์œผ๋กœ๋Š” ์ดํ‹€๊ฐ„์˜ ๋ฐฑํ…Œ์ŠคํŠธ ๊ฒฐ๊ณผ๋ฅผ **๋ฐ”๋กœ ์‹ค๋งค์— ์ ์šฉํ•˜๋Š” ๊ฒƒ์€ ์ ˆ๋Œ€ ๊ธˆ๋ฌผ**์ž…๋‹ˆ๋‹ค. **๊ณผ์ ํ•ฉ ์œ„ํ—˜(62.0%)๊ณผ ํ‘œ๋ณธ ๋ถ€์กฑ**์œผ๋กœ ์ธํ•ด ์‹ค๋งค ์‹œ **๋ฐฑํ…Œ์ŠคํŠธ์™€์˜ ๊ดด๋ฆฌ(๊ณ ์ŠคํŠธ ํผ์ง€ ๋“ฑ)๊ฐ€ ํด ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.** ์‚ฌํ›„ํ•ฉ๊ฒฉ 0๊ฑด์ด๋ฏ€๋กœ, **ํ˜„ํ–‰ DB๋ฅผ ์œ ์ง€**ํ•˜๋ฉฐ ์ตœ์†Œ 5๊ฑฐ๋ž˜์ผ ์ด์ƒ์œผ๋กœ ์žฌ๊ฒ€์ฆ ๋ฐ ์›น๋ฐฑํ…Œ์ŠคํŠธ๋ฅผ ๋ฐ˜๋“œ์‹œ ๊ฑฐ์ณ์•ผ ํ•ฉ๋‹ˆ๋‹ค. ํŠน์ • ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ํ™•์ • ์ˆ˜์ต์„ ์•ฝ์†ํ•  ์ˆ˜ ์—†์œผ๋ฉฐ, ์‹œ์žฅ ๋ณ€ํ™” ์‹œ ์†์ ˆ์ด ์ •์ƒ ์ž‘๋™ํ•˜๋Š”์ง€๋ฅผ ์ตœ์šฐ์„ ์œผ๋กœ ์ ๊ฒ€ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์–ด๋– ํ•œ ์ข…๋ชฉ ๋งค์ˆ˜๋„ ์ถ”์ฒœํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. diff --git a/kis_trader/backtest/results/optuna_tail_fast_20260904_232330.briefing.md b/kis_trader/backtest/results/optuna_tail_fast_20260904_232330.briefing.md new file mode 100644 index 0000000..8c2c896 --- /dev/null +++ b/kis_trader/backtest/results/optuna_tail_fast_20260904_232330.briefing.md @@ -0,0 +1,68 @@ +# Optuna ๋ธŒ๋ฆฌํ•‘ โ€” ๊ผฌ๋ฆฌ (fast) +๊ธฐ๊ฐ„: 2026-09-04 ~ 2026-09-04 (๊ฑฐ๋ž˜์ผโ‰ˆ1์ผ) ยท trials 10/10 +ํƒ์ƒ‰ ๊ฒŒ์ดํŠธ: WRโ‰ฅ0% PFโ‰ฅ0 ยท min_tradesโ‰ฅ1 | ํ›„๋ณด ๊ฒŒ์ดํŠธ: WRโ‰ฅ40% PFโ‰ฅ1 ยท min_tradesโ‰ฅ1 +- min_trades=1: **ํ•ฉ๊ฒฉ ์ธ์ • ์ตœ์†Œ ๊ฑฐ๋ž˜ ๊ฑด์ˆ˜**(ํ‘œ๋ณธ ๋ถ€์กฑยท์šฐ์—ฐ ์Šน๋ฅ  ๋ฐฉ์ง€). ์ด๋ณด๋‹ค ์ ์€ ์กฐํ•ฉ์€ ํ•™์Šต/ํ›„๋ณด ์ง‘๊ณ„์—์„œ ์ œ์™ธ๋ฉ๋‹ˆ๋‹ค. +ํ•™์Šต์šฉ ํ†ต๊ณผ 10๊ฑด ยท ์‚ฌํ›„ํ•ฉ๊ฒฉ(results_gated) 0๊ฑด + +## ๊ณผ์ ํ•ฉยท์ ์šฉ ๊ฐ€๋Šฅ๋„ (ํœด๋ฆฌ์Šคํ‹ฑ) +- **๊ณผ์ ํ•ฉ ์œ„ํ—˜ 52.0%** ยท **์ ์šฉ ๊ฐ€๋Šฅ๋„ 48.0%** ยท ํŒ์ •: **์ฃผ์˜** โ€” ์ ์šฉ ๊ฐ€๋Šฅ๋„ ์ค‘๊ฐ„ โ€” ๋‹ค์ผ(โ‰ฅ5์ผ) ์žฌ๊ฒ€์ฆยท์›น๋ฐฑํ…Œ ํ›„ ์†Œ์•ก๋งŒ + - ํ‘œ๋ณธ ์žฅ์ผ: +40.0p โ€” ๊ฑฐ๋ž˜์ผโ‰ˆ1์ผ โ€” ๋‹จ์ผ ์žฅ ๊ณผ์ ํ•ฉ ์œ„ํ—˜ ์ตœ๋Œ€ + - ๊ฑฐ๋ž˜ ํ‘œ๋ณธ: +0.0p โ€” ์ƒ์œ„ ํ›„๋ณด ๊ฑฐ๋ž˜ 32๊ฑด โ€” ์ƒ๋Œ€์  ์–‘ํ˜ธ + - ์Šน๋ฅ ยทPF ์ด์ƒ์น˜: +0.0p โ€” ์ด์ƒ์น˜ ์—†์Œ + - ๊ฒŒ์ดํŠธ ์ปค๋ฒ„: +12.0p โ€” ์‚ฌํ›„ํ•ฉ๊ฒฉ 0๊ฑด (ํ•™์Šต 10) โ€” DB ์ ์šฉ ๋น„๊ถŒ์žฅ + - PnL ๊ณ ์›: +0.0p โ€” ๊ณ ์› ๋น„์œจ 10% (1๊ฑด) +- ์ž„๊ณ„๊ฐ’ ๋ถ„ํฌ ํ‘œ๋ณธ: results(learning) ์ƒ์œ„ 10๊ฑด +| ํŒŒ๋ผ๋ฏธํ„ฐ | median | p25~p75 | mode(๋น„์œจ) | +|---|---:|---|---| +| `entry_mode` | โ€” | โ€” | align (100%) | +| `cand_limit` | 10.0 | 0.0 ~ 20.0 | 20 (50%) | +| `max_daily_change` | 35.0 | 31.25 ~ 35.0 | 35.0 (70%) | +| `min_drop_rate` | 0.03 | 0.01875 ~ 0.03 | 0.03 (70%) | +| `min_recovery_ratio` | 0.1 | 0.1 ~ 0.25 | 0.1 (60%) | +| `tail_ratio_min` | 0.8 | 0.6 ~ 1.0 | 0.6 (50%) | +| `tail_pct_min` | 0.001 | 0.001 ~ 0.005 | 0.001 (60%) | +| `max_rec_3m` | 0.85 | 0.85 ~ 0.9 | 0.85 (60%) | +| `shoulder_min_high` | 0.005 | 0.0035 ~ 0.007 | 0.007 (40%) | +| `shoulder_cut_pct` | 0.001 | 0.001 ~ 0.002 | 0.001 (60%) | +| `stop_atr_mult` | 1.75 | 1.125 ~ 2.0 | 2.0 (50%) | +| `target_atr_mult` | 2.0 | 1.5 ~ 2.5 | 2.5 (50%) | +- _์ฐธ๊ณ : ๊ณผ์ ํ•ฉ%๋Š” ๊ต์ฐจ๊ฒ€์ฆ ์ ์ˆ˜๊ฐ€ ์•„๋‹ˆ๋ผ ํ‘œ๋ณธยท์ด์ƒ์น˜ยท๊ณ ์› ํœด๋ฆฌ์Šคํ‹ฑ์ž…๋‹ˆ๋‹ค. ์ ์šฉ ๊ฐ€๋Šฅ๋„%=100โˆ’๊ณผ์ ํ•ฉ์œ„ํ—˜%. DB ์ ์šฉ ๋ฒ„ํŠผ ํ™œ์„ฑ ์กฐ๊ฑด(gated PnL>0)๊ณผ๋Š” ๋ณ„๊ฐœ์ž…๋‹ˆ๋‹ค._ + +## ์ตœ์ข… ์„ ํƒ ํ›„๋ณด (๊ทœ์น™ ยท DB ์ ์šฉ ์ „ ํ™•์ธ) +- ์•„๋ž˜๋Š” **์—ญํ• ์ด ๋‹ค๋ฅธ** 4์ข… ํ›„๋ณด์ž…๋‹ˆ๋‹ค. mode Top10 1์œ„ โ‰  ์ต์ ˆ ๋Œ€ํ‘œ ยท **DB 1์ˆœ์œ„๋Š” ์‚ฌํ›„ํ•ฉ๊ฒฉ(gated)** ์ž…๋‹ˆ๋‹ค. +- mode pool: `positive` ยท scoring: `band_proximity_p25_p75` + +### ํ›„๋ณด 4์ข… +- **โ‘  ์‚ฌํ›„ํ•ฉ๊ฒฉ 1์œ„ (apply: gated)**: ์—†์Œ +- **โ‘ก ์•ˆ์ • 1์œ„ (apply: stable)** (trial #6): PnL -16,382์› ยท WR 68.8% ยท PF 0.71 ยท ๊ฑฐ๋ž˜ 32๊ฑด ยท ์•ˆ์ •์ ์ˆ˜ -16491 ยท โ€” +- **โ‘ข mode_combo (apply: mode)** (trial ์—†์Œ(์กฐ๋ฆฝ)): PnL -2,347์› ยท WR 50.0% ยท PF 0.31 ยท ๊ฑฐ๋ž˜ 2๊ฑด ยท ์•ˆ์ •์ ์ˆ˜ -2347 ยท โ€” +- **โ‘ฃ mode Top10 1์œ„ (apply: consensus ยท ๋ฐด๋“œ ์ „ํ˜• trial)** (trial #7): PnL -39,784์› ยท WR 47.1% ยท PF 0.44 ยท ๊ฑฐ๋ž˜ 17๊ฑด ยท ์•ˆ์ •์ ์ˆ˜ -42508 ยท ๊ทผ์ ‘ 99.1% (33/35์ถ• ๋ฐด๋“œ์•ˆ) ยท โ€” +- mode Top10 meta: pool 10๊ฑด ยท ์ถ• 35๊ฐœ + +### ์ถ”์ฒœ (์ž๋™ ยท confirm ํ•„์ˆ˜) +1. **์‚ฌํ›„ํ•ฉ๊ฒฉ 0๊ฑด โ†’ DB ์ ์šฉ ๋น„๊ถŒ์žฅ.** ํ˜„ํ–‰ DB ์œ ์ง€ + ์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑยท๊ธฐ๊ฐ„ ์žฌ๊ฒ€์ฆ. +2. ์ฐธ๊ณ ๋งŒ: ํ•™์Šต 1์œ„๋Š” objective ์ตœ๋Œ€์ผ ๋ฟ ์‚ฌํ›„ ๊ฒŒ์ดํŠธ ๋ฏธํ†ต๊ณผ์ผ ์ˆ˜ ์žˆ์Œ. +2. **2์ฐจ narrowยท๋Œ€ํ‘œ ์ˆซ์ž โ†’ โ‘ข mode_combo** โ€” ์ถ•๋ณ„ ์ตœ๋นˆ ์กฐ๋ฆฝ ยท trial ๋ฒˆํ˜ธ ์—†์Œ ยท ์ต์ ˆ์€ pool ์ตœ๋นˆ๊ฐ’ ์ฐธ๊ณ . +3. **โ‘ฃ mode Top10 1์œ„** โ€” ์–‘์ˆ˜ pool ์ „ํ˜• trial(๋‹ค์ถ• ๋ฐด๋“œ ๊ทผ์ ‘). **์ต์ ˆ ํ•˜๋‚˜๋กœ ์“ฐ์ง€ ๋ง ๊ฒƒ** ยท ํ‘œ์—์„œ ใ€Œ๋ณด๊ธฐใ€โ†’ consensus apply. + +## ์ด์ „ ์žฅ์—์„œ๋Š” +- ์‹ค๋งค ๋™๊ธฐ๊ฐ„ ์ฒญ์‚ฐ 8๊ฑด ยท ์Šน๋ฅ  50% ยท ํ•ฉ์‚ฐ PnL 121,682์› (๋ฐฑํ…Œ Optuna์™€ ์ˆซ์ž ๋‹ฌ๋ผ๋„ ์ •์ƒ โ€” ๊ณ ์ŠคํŠธยท์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑ ๊ฒฝ๋กœ ์ฐจ์ด). +- ํ•™์Šต 1์œ„(์‚ฌํ›„๊ฒŒ์ดํŠธ ๋ฏธ๋‹ฌ ๊ฐ€๋Šฅ): trial #6 ยท ๊ฑฐ๋ž˜ 32๊ฑด ยท ์Šน๋ฅ  68.8% ยท PF 0.71 ยท PnL -16,382์› +- ํ‘œ๋ณธ ์žฅ์ด 1์ผ๋ฟ์ด๋ผ, โ€˜์ด์ „ ์žฅ์— ์ž˜ ๋จนํžŒ ์ˆซ์žโ€™์ผ ๋ฟ **์ถ”์„ธ๊ฐ€ ๋ฐ”๋€Œ๋ฉด ๋ฐ”๋กœ ๊นจ์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.** +- ํ”Œ๋Ÿฌ์Šค/ํ•™์Šต ํ›„๋ณด๋Š” ์žˆ์œผ๋‚˜ ์Šน๋ฅ ยทPF ์‚ฌํ›„ ๊ธฐ์ค€์€ ๋ชป ๋„˜๊น€ โ†’ **๋‹น์žฅ DB ์ ์šฉ์€ ๋น„๊ถŒ์žฅ.** + +## ์•ž์œผ๋กœ ์žฅ์—์„œ๋Š” +- **1~2์ผ Optuna best๋ฅผ ๋ฐ”๋กœ ์‹ค๋งค์— ๋„ฃ์ง€ ๋งˆ์„ธ์š”.** ๋‹ค์ผ(โ‰ฅ5๊ฑฐ๋ž˜์ผ) ์žฌ๊ฒ€์ฆยท์›น๋ฐฑํ…Œ 1ํšŒ ํ›„ ๊ฒ€ํ† . +- ์ ์šฉ ์‹œ์—๋Š” `results_gated` ํ›„๋ณด๋งŒ. ํƒ์ƒ‰์šฉ best(objective)์™€ ๋‹ค๋ฅผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. +- ์žฅ์ด ์ข์•„์ง€๊ฑฐ๋‚˜ ๋ณ€๋™์„ฑ์ด ์ปค์ง€๋ฉด: ์†์ ˆยทํŠธ๋ ˆ์ผยท์‹œ๊ฐ„์ฐฝ์ด ๋จผ์ € ๊นจ์ง‘๋‹ˆ๋‹ค. ์Šน๋ฅ  ์ž๋ž‘๋ณด๋‹ค **์†์ ˆ์ด ์‚ด์•„ ์žˆ๋Š”์ง€**๋ฅผ ๋ณด์„ธ์š”. +- ํ˜„์žฌ ์‚ฌํ›„ํ•ฉ๊ฒฉ 0๊ฑด โ†’ ํŒŒ๋ผ๋ฏธํ„ฐ ์œ ์ง€(ํ˜„ํ–‰ DB) + ์œ ๋‹ˆ๋ฒ„์Šค/๋ฐ์ดํ„ฐ ์ ๊ฒ€์ด ์šฐ์„ ์ž…๋‹ˆ๋‹ค. + +_์ƒ์„ฑ: 2026-09-04 23:23:32 (rule)_ + +## AI ์ฝ”๋ฉ˜ํŠธ (์ด์ „ ์žฅ / ์•ž์œผ๋กœ ์žฅ) [gemini] + +**์ด์ „ ์žฅ์—์„œ๋Š”** +๋‹จ ํ•˜๋ฃจ์˜ ๋ฐฑํ…Œ์ŠคํŠธ ๊ฒฐ๊ณผ๋Š” 52%์˜ ๋†’์€ ๊ณผ์ ํ•ฉ ์œ„ํ—˜์„ ๋ณด์˜€์Šต๋‹ˆ๋‹ค. ์‹ฌ์ง€์–ด ํ•™์Šต ์ƒ์œ„ 1์œ„ ์ „๋žต์กฐ์ฐจ ์†์‹ค(-16,382์›)์„ ๊ธฐ๋กํ–ˆ๊ณ , ๋ผ์ด๋ธŒ ์ ์šฉ์„ ์œ„ํ•œ ์ตœ์†Œ ์ด์ต๋ฅ (PF 1.0) ๊ธฐ์ค€์„ ์ถฉ์กฑํ•˜์ง€ ๋ชปํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด์ „ ์‹ค์ œ ๊ฑฐ๋ž˜๋Š” ๊ธ์ •์ ์ด์—ˆ์œผ๋‚˜, ์ด๋Š” ๋ฐฑํ…Œ์ŠคํŠธ์™€ ๋‹ค๋ฅธ ์กฐ๊ฑด(๊ณ ์ŠคํŠธํผ์ง€, ์œ ๋‹ˆ๋ฒ„์Šค ๋“ฑ)์—์„œ ๋ฐœ์ƒํ–ˆ์œผ๋ฏ€๋กœ ๋‹จ์ˆœ ๋น„๊ต๋Š” ์–ด๋ ต์Šต๋‹ˆ๋‹ค. ์‚ฌํ›„ํ•ฉ๊ฒฉ(gated)๋œ ์ „๋žต์ด ์ „ํ˜€ ์—†์–ด, ํ˜„์žฌ๋กœ์„  ์‹ ๋ขฐํ•  ๋งŒํ•œ ๋ผ์ด๋ธŒ ์ ์šฉ ํ›„๋ณด๋ฅผ ์ฐพ์ง€ ๋ชปํ–ˆ์Šต๋‹ˆ๋‹ค. + +**์•ž์œผ๋กœ ์žฅ์—์„œ๋Š”** +๋‹จ๊ธฐ ๋ฐฑํ…Œ์ŠคํŠธ ๊ฒฐ๊ณผ๋Š” ๊ณผ์ ํ•ฉ๊ณผ ํ‘œ๋ณธ ๋ถ€์กฑ์œผ๋กœ ์ธํ•ด ์‹ค์ œ ์‹œ์žฅ์—์„œ ์‰ฝ๊ฒŒ ๋ฌด๋ ฅํ™”๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ์ตœ์†Œ 5์ผ ์ด์ƒ์˜ ๋‹ค์ผ(ๅคšๆ—ฅ) ์žฌ๊ฒ€์ฆ๊ณผ ์›น ๋ฐฑํ…Œ์ŠคํŠธ๋ฅผ ๋จผ์ € ์ˆ˜ํ–‰ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์‹ค์ œ ๊ฑฐ๋ž˜์—์„œ๋Š” ๋ฐฑํ…Œ์ŠคํŠธ์™€ ๊ดด๋ฆฌ(๊ณ ์ŠคํŠธํผ์ง€, ์Šฌ๋ฆฌํ”ผ์ง€ ๋“ฑ)๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์œผ๋‹ˆ ์„ฃ๋ถ€๋ฅธ ์ ์šฉ์€ ๊ธˆ๋ฌผ์ž…๋‹ˆ๋‹ค. ๋†’์€ ์Šน๋ฅ ๋ณด๋‹ค๋Š” ์†์ ˆ ๋ฉ”์ปค๋‹ˆ์ฆ˜์ด ์‹œ์žฅ ๋ณ€๋™์„ฑ ์†์—์„œ๋„ ๊ฒฌ๊ณ ํ•˜๊ฒŒ ์ž‘๋™ํ•˜๋Š”์ง€ ํ™•์ธํ•˜๋Š” ๊ฒƒ์ด ๊ฐ€์žฅ ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค. ํ˜„์žฌ ์‚ฌํ›„ํ•ฉ๊ฒฉ๋œ ์ „๋žต์ด ์—†์œผ๋ฏ€๋กœ, ๊ธฐ์กด DB ์œ ์ง€ ๋ฐ ๋ฐ์ดํ„ฐ ์ ๊ฒ€์„ ์šฐ์„ ํ•˜๋ฉฐ, ํŠน์ • ์ข…๋ชฉ ๋งค์ˆ˜ ์ถ”์ฒœ์ด๋‚˜ ํ™•์ • ์ˆ˜์ต์€ ๋ณด์žฅํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. diff --git a/kis_trader/backtest/results/optuna_tail_fast_20260904_232420.briefing.md b/kis_trader/backtest/results/optuna_tail_fast_20260904_232420.briefing.md new file mode 100644 index 0000000..77339b3 --- /dev/null +++ b/kis_trader/backtest/results/optuna_tail_fast_20260904_232420.briefing.md @@ -0,0 +1,68 @@ +# Optuna ๋ธŒ๋ฆฌํ•‘ โ€” ๊ผฌ๋ฆฌ (fast) +๊ธฐ๊ฐ„: 2026-09-04 ~ 2026-09-04 (๊ฑฐ๋ž˜์ผโ‰ˆ1์ผ) ยท trials 10/10 +ํƒ์ƒ‰ ๊ฒŒ์ดํŠธ: WRโ‰ฅ0% PFโ‰ฅ0 ยท min_tradesโ‰ฅ1 | ํ›„๋ณด ๊ฒŒ์ดํŠธ: WRโ‰ฅ40% PFโ‰ฅ1 ยท min_tradesโ‰ฅ1 +- min_trades=1: **ํ•ฉ๊ฒฉ ์ธ์ • ์ตœ์†Œ ๊ฑฐ๋ž˜ ๊ฑด์ˆ˜**(ํ‘œ๋ณธ ๋ถ€์กฑยท์šฐ์—ฐ ์Šน๋ฅ  ๋ฐฉ์ง€). ์ด๋ณด๋‹ค ์ ์€ ์กฐํ•ฉ์€ ํ•™์Šต/ํ›„๋ณด ์ง‘๊ณ„์—์„œ ์ œ์™ธ๋ฉ๋‹ˆ๋‹ค. +ํ•™์Šต์šฉ ํ†ต๊ณผ 10๊ฑด ยท ์‚ฌํ›„ํ•ฉ๊ฒฉ(results_gated) 0๊ฑด + +## ๊ณผ์ ํ•ฉยท์ ์šฉ ๊ฐ€๋Šฅ๋„ (ํœด๋ฆฌ์Šคํ‹ฑ) +- **๊ณผ์ ํ•ฉ ์œ„ํ—˜ 52.0%** ยท **์ ์šฉ ๊ฐ€๋Šฅ๋„ 48.0%** ยท ํŒ์ •: **์ฃผ์˜** โ€” ์ ์šฉ ๊ฐ€๋Šฅ๋„ ์ค‘๊ฐ„ โ€” ๋‹ค์ผ(โ‰ฅ5์ผ) ์žฌ๊ฒ€์ฆยท์›น๋ฐฑํ…Œ ํ›„ ์†Œ์•ก๋งŒ + - ํ‘œ๋ณธ ์žฅ์ผ: +40.0p โ€” ๊ฑฐ๋ž˜์ผโ‰ˆ1์ผ โ€” ๋‹จ์ผ ์žฅ ๊ณผ์ ํ•ฉ ์œ„ํ—˜ ์ตœ๋Œ€ + - ๊ฑฐ๋ž˜ ํ‘œ๋ณธ: +0.0p โ€” ์ƒ์œ„ ํ›„๋ณด ๊ฑฐ๋ž˜ 22๊ฑด โ€” ์ƒ๋Œ€์  ์–‘ํ˜ธ + - ์Šน๋ฅ ยทPF ์ด์ƒ์น˜: +0.0p โ€” ์ด์ƒ์น˜ ์—†์Œ + - ๊ฒŒ์ดํŠธ ์ปค๋ฒ„: +12.0p โ€” ์‚ฌํ›„ํ•ฉ๊ฒฉ 0๊ฑด (ํ•™์Šต 10) โ€” DB ์ ์šฉ ๋น„๊ถŒ์žฅ + - PnL ๊ณ ์›: +0.0p โ€” ๊ณ ์› ๋น„์œจ 10% (1๊ฑด) +- ์ž„๊ณ„๊ฐ’ ๋ถ„ํฌ ํ‘œ๋ณธ: results(learning) ์ƒ์œ„ 10๊ฑด +| ํŒŒ๋ผ๋ฏธํ„ฐ | median | p25~p75 | mode(๋น„์œจ) | +|---|---:|---|---| +| `entry_mode` | โ€” | โ€” | align (100%) | +| `cand_limit` | 0.0 | 0.0 ~ 20.0 | 0 (60%) | +| `max_daily_change` | 30.0 | 30.0 ~ 35.0 | 30.0 (60%) | +| `min_drop_rate` | 0.03 | 0.015 ~ 0.03 | 0.03 (60%) | +| `min_recovery_ratio` | 0.1 | 0.1 ~ 0.2125 | 0.1 (70%) | +| `tail_ratio_min` | 0.8 | 0.6 ~ 1.0 | 0.6 (50%) | +| `tail_pct_min` | 0.003 | 0.001 ~ 0.005 | 0.005 (50%) | +| `max_rec_3m` | 0.9 | 0.85 ~ 0.9 | 0.9 (60%) | +| `shoulder_min_high` | 0.005 | 0.005 ~ 0.007 | 0.005 (50%) | +| `shoulder_cut_pct` | 0.001 | 0.001 ~ 0.00175 | 0.001 (70%) | +| `stop_atr_mult` | 2.0 | 1.5 ~ 2.0 | 2.0 (60%) | +| `target_atr_mult` | 1.5 | 1.125 ~ 2.5 | 2.5 (40%) | +- _์ฐธ๊ณ : ๊ณผ์ ํ•ฉ%๋Š” ๊ต์ฐจ๊ฒ€์ฆ ์ ์ˆ˜๊ฐ€ ์•„๋‹ˆ๋ผ ํ‘œ๋ณธยท์ด์ƒ์น˜ยท๊ณ ์› ํœด๋ฆฌ์Šคํ‹ฑ์ž…๋‹ˆ๋‹ค. ์ ์šฉ ๊ฐ€๋Šฅ๋„%=100โˆ’๊ณผ์ ํ•ฉ์œ„ํ—˜%. DB ์ ์šฉ ๋ฒ„ํŠผ ํ™œ์„ฑ ์กฐ๊ฑด(gated PnL>0)๊ณผ๋Š” ๋ณ„๊ฐœ์ž…๋‹ˆ๋‹ค._ + +## ์ตœ์ข… ์„ ํƒ ํ›„๋ณด (๊ทœ์น™ ยท DB ์ ์šฉ ์ „ ํ™•์ธ) +- ์•„๋ž˜๋Š” **์—ญํ• ์ด ๋‹ค๋ฅธ** 4์ข… ํ›„๋ณด์ž…๋‹ˆ๋‹ค. mode Top10 1์œ„ โ‰  ์ต์ ˆ ๋Œ€ํ‘œ ยท **DB 1์ˆœ์œ„๋Š” ์‚ฌํ›„ํ•ฉ๊ฒฉ(gated)** ์ž…๋‹ˆ๋‹ค. +- mode pool: `positive` ยท scoring: `band_proximity_p25_p75` + +### ํ›„๋ณด 4์ข… +- **โ‘  ์‚ฌํ›„ํ•ฉ๊ฒฉ 1์œ„ (apply: gated)**: ์—†์Œ +- **โ‘ก ์•ˆ์ • 1์œ„ (apply: stable)** (trial #3): PnL -23,360์› ยท WR 59.1% ยท PF 0.67 ยท ๊ฑฐ๋ž˜ 22๊ฑด ยท ์•ˆ์ •์ ์ˆ˜ -26084 ยท โ€” +- **โ‘ข mode_combo (apply: mode)** (trial ์—†์Œ(์กฐ๋ฆฝ)): PnL 0์› ยท WR 0.0% ยท PF 0.00 ยท ๊ฑฐ๋ž˜ 0๊ฑด ยท โ€” +- **โ‘ฃ mode Top10 1์œ„ (apply: consensus ยท ๋ฐด๋“œ ์ „ํ˜• trial)** (trial #4): PnL -39,784์› ยท WR 47.1% ยท PF 0.44 ยท ๊ฑฐ๋ž˜ 17๊ฑด ยท ์•ˆ์ •์ ์ˆ˜ -42508 ยท ๊ทผ์ ‘ 99.8% (34/35์ถ• ๋ฐด๋“œ์•ˆ) ยท โ€” +- mode Top10 meta: pool 10๊ฑด ยท ์ถ• 35๊ฐœ + +### ์ถ”์ฒœ (์ž๋™ ยท confirm ํ•„์ˆ˜) +1. **์‚ฌํ›„ํ•ฉ๊ฒฉ 0๊ฑด โ†’ DB ์ ์šฉ ๋น„๊ถŒ์žฅ.** ํ˜„ํ–‰ DB ์œ ์ง€ + ์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑยท๊ธฐ๊ฐ„ ์žฌ๊ฒ€์ฆ. +2. ์ฐธ๊ณ ๋งŒ: ํ•™์Šต 1์œ„๋Š” objective ์ตœ๋Œ€์ผ ๋ฟ ์‚ฌํ›„ ๊ฒŒ์ดํŠธ ๋ฏธํ†ต๊ณผ์ผ ์ˆ˜ ์žˆ์Œ. +2. **2์ฐจ narrowยท๋Œ€ํ‘œ ์ˆซ์ž โ†’ โ‘ข mode_combo** โ€” ์ถ•๋ณ„ ์ตœ๋นˆ ์กฐ๋ฆฝ ยท trial ๋ฒˆํ˜ธ ์—†์Œ ยท ์ต์ ˆ์€ pool ์ตœ๋นˆ๊ฐ’ ์ฐธ๊ณ . +3. **โ‘ฃ mode Top10 1์œ„** โ€” ์–‘์ˆ˜ pool ์ „ํ˜• trial(๋‹ค์ถ• ๋ฐด๋“œ ๊ทผ์ ‘). **์ต์ ˆ ํ•˜๋‚˜๋กœ ์“ฐ์ง€ ๋ง ๊ฒƒ** ยท ํ‘œ์—์„œ ใ€Œ๋ณด๊ธฐใ€โ†’ consensus apply. + +## ์ด์ „ ์žฅ์—์„œ๋Š” +- ์‹ค๋งค ๋™๊ธฐ๊ฐ„ ์ฒญ์‚ฐ 8๊ฑด ยท ์Šน๋ฅ  50% ยท ํ•ฉ์‚ฐ PnL 121,682์› (๋ฐฑํ…Œ Optuna์™€ ์ˆซ์ž ๋‹ฌ๋ผ๋„ ์ •์ƒ โ€” ๊ณ ์ŠคํŠธยท์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑ ๊ฒฝ๋กœ ์ฐจ์ด). +- ํ•™์Šต 1์œ„(์‚ฌํ›„๊ฒŒ์ดํŠธ ๋ฏธ๋‹ฌ ๊ฐ€๋Šฅ): trial #3 ยท ๊ฑฐ๋ž˜ 22๊ฑด ยท ์Šน๋ฅ  59.1% ยท PF 0.67 ยท PnL -23,360์› +- ํ‘œ๋ณธ ์žฅ์ด 1์ผ๋ฟ์ด๋ผ, โ€˜์ด์ „ ์žฅ์— ์ž˜ ๋จนํžŒ ์ˆซ์žโ€™์ผ ๋ฟ **์ถ”์„ธ๊ฐ€ ๋ฐ”๋€Œ๋ฉด ๋ฐ”๋กœ ๊นจ์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.** +- ํ”Œ๋Ÿฌ์Šค/ํ•™์Šต ํ›„๋ณด๋Š” ์žˆ์œผ๋‚˜ ์Šน๋ฅ ยทPF ์‚ฌํ›„ ๊ธฐ์ค€์€ ๋ชป ๋„˜๊น€ โ†’ **๋‹น์žฅ DB ์ ์šฉ์€ ๋น„๊ถŒ์žฅ.** + +## ์•ž์œผ๋กœ ์žฅ์—์„œ๋Š” +- **1~2์ผ Optuna best๋ฅผ ๋ฐ”๋กœ ์‹ค๋งค์— ๋„ฃ์ง€ ๋งˆ์„ธ์š”.** ๋‹ค์ผ(โ‰ฅ5๊ฑฐ๋ž˜์ผ) ์žฌ๊ฒ€์ฆยท์›น๋ฐฑํ…Œ 1ํšŒ ํ›„ ๊ฒ€ํ† . +- ์ ์šฉ ์‹œ์—๋Š” `results_gated` ํ›„๋ณด๋งŒ. ํƒ์ƒ‰์šฉ best(objective)์™€ ๋‹ค๋ฅผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. +- ์žฅ์ด ์ข์•„์ง€๊ฑฐ๋‚˜ ๋ณ€๋™์„ฑ์ด ์ปค์ง€๋ฉด: ์†์ ˆยทํŠธ๋ ˆ์ผยท์‹œ๊ฐ„์ฐฝ์ด ๋จผ์ € ๊นจ์ง‘๋‹ˆ๋‹ค. ์Šน๋ฅ  ์ž๋ž‘๋ณด๋‹ค **์†์ ˆ์ด ์‚ด์•„ ์žˆ๋Š”์ง€**๋ฅผ ๋ณด์„ธ์š”. +- ํ˜„์žฌ ์‚ฌํ›„ํ•ฉ๊ฒฉ 0๊ฑด โ†’ ํŒŒ๋ผ๋ฏธํ„ฐ ์œ ์ง€(ํ˜„ํ–‰ DB) + ์œ ๋‹ˆ๋ฒ„์Šค/๋ฐ์ดํ„ฐ ์ ๊ฒ€์ด ์šฐ์„ ์ž…๋‹ˆ๋‹ค. + +_์ƒ์„ฑ: 2026-09-04 23:24:21 (rule)_ + +## AI ์ฝ”๋ฉ˜ํŠธ (์ด์ „ ์žฅ / ์•ž์œผ๋กœ ์žฅ) [gemini] + +## ์ด์ „ ์žฅ์—์„œ๋Š” +๋‹จ ํ•˜๋ฃจ(1์ผ) ๋ฐฑํ…Œ์ŠคํŠธ๋กœ **๊ณผ์ ํ•ฉ ์œ„ํ—˜์ด ๋งค์šฐ ํฝ๋‹ˆ๋‹ค.** ์‚ฌํ›„ํ•ฉ๊ฒฉ๋œ ์ „๋žต์ด ์—†์–ด ์‹ค๋งค ์ ์šฉ์€ ๋น„๊ถŒ์žฅ๋ฉ๋‹ˆ๋‹ค. ํ•™์Šต 1์œ„ ์ „๋žต๋„ ์†์‹ค(-2.3๋งŒ์›)์„ ๋ณด์˜€๊ณ , ์‹ค๋งค ๊ฒฐ๊ณผ(12.1๋งŒ์› ์ˆ˜์ต)์™€ ๋ฐฑํ…Œ์ŠคํŠธ๋Š” **์‹ค๋งค-๋ฐฑํ…Œ ๊ดด๋ฆฌ(๊ณ ์ŠคํŠธํผ์ง€)**๊ฐ€ ์žˆ์œผ๋‹ˆ ์œ ์˜ํ•˜์„ธ์š”. + +## ์•ž์œผ๋กœ ์žฅ์—์„œ๋Š” +์ด์ฒ˜๋Ÿผ **ํ‘œ๋ณธ์ด ๋ถ€์กฑํ•˜๊ณ  ๊ณผ์ ํ•ฉ๋œ 1์ผ ๋ฐฑํ…Œ์ŠคํŠธ ๊ฒฐ๊ณผ๋Š” ์ ˆ๋Œ€ ์‹ค๋งค์— ๋ฐ”๋กœ ์“ฐ์ง€ ๋งˆ์„ธ์š”.** ์‚ฌํ›„ํ•ฉ๊ฒฉ ์ „๋žต์ด ์—†์œผ๋ฏ€๋กœ, ํ˜„์žฌ DB๋ฅผ ์œ ์ง€ํ•˜๊ณ  ์ตœ์†Œ 5์ผ ์ด์ƒ ๋‹ค์ผ ๊ฒ€์ฆ๊ณผ ์›น๋ฐฑํ…Œ์ŠคํŠธ๋ฅผ ๊ผญ ๊ฑฐ์ณ์•ผ ํ•ฉ๋‹ˆ๋‹ค. **ํ™•์ • ์ˆ˜์ต์€ ์—†์œผ๋ฉฐ, ๋ฐฑํ…Œ์ŠคํŠธ์™€ ์‹ค๋งค์˜ ๊ดด๋ฆฌ์— ๋Š˜ ๋Œ€๋น„ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.** ์ˆ˜์ต๋ฅ ๋ณด๋‹ค **์†์ ˆ ๊ธฐ๋Šฅ** ๊ฒ€์ฆ์ด ์ตœ์šฐ์„ ์ž…๋‹ˆ๋‹ค. diff --git a/kis_trader/backtest/results/optuna_tail_tpe_20260903_025146.briefing.md b/kis_trader/backtest/results/optuna_tail_tpe_20260903_025146.briefing.md new file mode 100644 index 0000000..8a36341 --- /dev/null +++ b/kis_trader/backtest/results/optuna_tail_tpe_20260903_025146.briefing.md @@ -0,0 +1,49 @@ +# Optuna ๋ธŒ๋ฆฌํ•‘ โ€” ๊ผฌ๋ฆฌ (tpe) +๊ธฐ๊ฐ„: 2026-08-24 ~ 2026-08-28 (๊ฑฐ๋ž˜์ผโ‰ˆ5์ผ) ยท trials 200/200 +ํƒ์ƒ‰ ๊ฒŒ์ดํŠธ: WRโ‰ฅ0% PFโ‰ฅ0 ยท min_tradesโ‰ฅ1 | ํ›„๋ณด ๊ฒŒ์ดํŠธ: WRโ‰ฅ40% PFโ‰ฅ1 ยท min_tradesโ‰ฅ1 +- min_trades=1: **ํ•ฉ๊ฒฉ ์ธ์ • ์ตœ์†Œ ๊ฑฐ๋ž˜ ๊ฑด์ˆ˜**(ํ‘œ๋ณธ ๋ถ€์กฑยท์šฐ์—ฐ ์Šน๋ฅ  ๋ฐฉ์ง€). ์ด๋ณด๋‹ค ์ ์€ ์กฐํ•ฉ์€ ํ•™์Šต/ํ›„๋ณด ์ง‘๊ณ„์—์„œ ์ œ์™ธ๋ฉ๋‹ˆ๋‹ค. +ํ•™์Šต์šฉ ํ†ต๊ณผ 0๊ฑด ยท ์‚ฌํ›„ํ•ฉ๊ฒฉ(results_gated) 0๊ฑด + +## ๊ณผ์ ํ•ฉยท์ ์šฉ ๊ฐ€๋Šฅ๋„ (ํœด๋ฆฌ์Šคํ‹ฑ) +- **๊ณผ์ ํ•ฉ ์œ„ํ—˜ 33.0%** ยท **์ ์šฉ ๊ฐ€๋Šฅ๋„ 67.0%** ยท ํŒ์ •: **์ƒ๋Œ€์ ์œผ๋กœ๋‚ฎ์Œ** โ€” ํœด๋ฆฌ์Šคํ‹ฑ์ƒ ์œ„ํ—˜ ์ƒ๋Œ€์  ๋‚ฎ์Œ โ€” ๊ทธ๋ž˜๋„ ๋‹ค์ผ ํ™•์ธ ๊ถŒ์žฅ + - ํ‘œ๋ณธ ์žฅ์ผ: +0.0p โ€” ๊ฑฐ๋ž˜์ผโ‰ˆ5์ผ โ€” ํ‘œ๋ณธ ์ผ์ˆ˜ ์ƒ๋Œ€์  ์–‘ํ˜ธ + - ๊ฑฐ๋ž˜ ํ‘œ๋ณธ: +25.0p โ€” ํ†ต๊ณผ ํ›„๋ณด ์—†์Œ โ€” ์ ์šฉ ๋ถˆ๊ฐ€ + - ์Šน๋ฅ ยทPF ์ด์ƒ์น˜: +0.0p โ€” ์ด์ƒ์น˜ ์—†์Œ + - ๊ฒŒ์ดํŠธ ์ปค๋ฒ„: +8.0p โ€” ํ•™์Šตยทgated ๋ชจ๋‘ ๋น„์–ด ์žˆ์Œ + - PnL ๊ณ ์›: +0.0p โ€” ๊ณ ์› ํŒ์ • ์Šคํ‚ต +- _์ฐธ๊ณ : ๊ณผ์ ํ•ฉ%๋Š” ๊ต์ฐจ๊ฒ€์ฆ ์ ์ˆ˜๊ฐ€ ์•„๋‹ˆ๋ผ ํ‘œ๋ณธยท์ด์ƒ์น˜ยท๊ณ ์› ํœด๋ฆฌ์Šคํ‹ฑ์ž…๋‹ˆ๋‹ค. ์ ์šฉ ๊ฐ€๋Šฅ๋„%=100โˆ’๊ณผ์ ํ•ฉ์œ„ํ—˜%. DB ์ ์šฉ ๋ฒ„ํŠผ ํ™œ์„ฑ ์กฐ๊ฑด(gated PnL>0)๊ณผ๋Š” ๋ณ„๊ฐœ์ž…๋‹ˆ๋‹ค._ + +## ์ตœ์ข… ์„ ํƒ ํ›„๋ณด (๊ทœ์น™ ยท DB ์ ์šฉ ์ „ ํ™•์ธ) +- ์•„๋ž˜๋Š” **์—ญํ• ์ด ๋‹ค๋ฅธ** 4์ข… ํ›„๋ณด์ž…๋‹ˆ๋‹ค. mode Top10 1์œ„ โ‰  ์ต์ ˆ ๋Œ€ํ‘œ ยท **DB 1์ˆœ์œ„๋Š” ์‚ฌํ›„ํ•ฉ๊ฒฉ(gated)** ์ž…๋‹ˆ๋‹ค. +- mode pool: `positive` ยท scoring: `band_proximity_p25_p75` + +### ํ›„๋ณด 4์ข… +- **โ‘  ์‚ฌํ›„ํ•ฉ๊ฒฉ 1์œ„ (apply: gated)**: ์—†์Œ +- **โ‘ก ์•ˆ์ • 1์œ„ (apply: stable)**: ์—†์Œ +- **โ‘ข mode_combo (apply: mode)**: ์—†์Œ (๋ฏธ์‚ฐ์ถœยท๊ตฌ JSON) +- **โ‘ฃ mode Top10 1์œ„ (apply: consensus ยท ๋ฐด๋“œ ์ „ํ˜• trial)**: ์—†์Œ +- mode Top10 meta: pool 0๊ฑด ยท ์ถ• 0๊ฐœ + +### ์ถ”์ฒœ (์ž๋™ ยท confirm ํ•„์ˆ˜) +1. **์‚ฌํ›„ํ•ฉ๊ฒฉ 0๊ฑด โ†’ DB ์ ์šฉ ๋น„๊ถŒ์žฅ.** ํ˜„ํ–‰ DB ์œ ์ง€ + ์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑยท๊ธฐ๊ฐ„ ์žฌ๊ฒ€์ฆ. +- โš  ์•ˆ์ • ๊ฒŒ์ดํŠธ 0๊ฑด โ†’ ์•ˆ์ • Top์€ **์ ์ˆ˜์ˆœ ํด๋ฐฑ** (์•ˆ์ • ๊ฒŒ์ดํŠธ 0๊ฑด โ†’ ํ•™์Šตํ’€ ์•ˆ์ •์ ์ˆ˜์ˆœ TopN (๋งˆ์ด๋„ˆ์Šค PnL ํฌํ•จ ยท ์ƒ๋Œ€๋น„๊ต)) + +## ์ด์ „ ์žฅ์—์„œ๋Š” +- ์‹ค๋งค ๋™๊ธฐ๊ฐ„ ์ฒญ์‚ฐ 6๊ฑด ยท ์Šน๋ฅ  67% ยท ํ•ฉ์‚ฐ PnL -9,520์› (๋ฐฑํ…Œ Optuna์™€ ์ˆซ์ž ๋‹ฌ๋ผ๋„ ์ •์ƒ โ€” ๊ณ ์ŠคํŠธยท์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑ ๊ฒฝ๋กœ ์ฐจ์ด). +- ์ด ๊ธฐ๊ฐ„ ๋ฐฑํ…Œ์—์„œ๋Š” **์œ ์˜๋ฏธํ•œ ํ†ต๊ณผ ์กฐํ•ฉ์ด ๊ฑฐ์˜ ์—†์—ˆ์Šต๋‹ˆ๋‹ค.** ์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑยท์†์ ˆยท์‹œ๊ฐ„์ฐฝ์„ ๋จผ์ € ์ ๊ฒ€ํ•˜์„ธ์š” (๋ŒํŒŒ 0๊ฑด์ด๋ฉด ํŠนํžˆ). + +## ์•ž์œผ๋กœ ์žฅ์—์„œ๋Š” +- **1~2์ผ Optuna best๋ฅผ ๋ฐ”๋กœ ์‹ค๋งค์— ๋„ฃ์ง€ ๋งˆ์„ธ์š”.** ๋‹ค์ผ(โ‰ฅ5๊ฑฐ๋ž˜์ผ) ์žฌ๊ฒ€์ฆยท์›น๋ฐฑํ…Œ 1ํšŒ ํ›„ ๊ฒ€ํ† . +- ์ ์šฉ ์‹œ์—๋Š” `results_gated` ํ›„๋ณด๋งŒ. ํƒ์ƒ‰์šฉ best(objective)์™€ ๋‹ค๋ฅผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. +- ์žฅ์ด ์ข์•„์ง€๊ฑฐ๋‚˜ ๋ณ€๋™์„ฑ์ด ์ปค์ง€๋ฉด: ์†์ ˆยทํŠธ๋ ˆ์ผยท์‹œ๊ฐ„์ฐฝ์ด ๋จผ์ € ๊นจ์ง‘๋‹ˆ๋‹ค. ์Šน๋ฅ  ์ž๋ž‘๋ณด๋‹ค **์†์ ˆ์ด ์‚ด์•„ ์žˆ๋Š”์ง€**๋ฅผ ๋ณด์„ธ์š”. +- ํ˜„์žฌ ์‚ฌํ›„ํ•ฉ๊ฒฉ 0๊ฑด โ†’ ํŒŒ๋ผ๋ฏธํ„ฐ ์œ ์ง€(ํ˜„ํ–‰ DB) + ์œ ๋‹ˆ๋ฒ„์Šค/๋ฐ์ดํ„ฐ ์ ๊ฒ€์ด ์šฐ์„ ์ž…๋‹ˆ๋‹ค. + +_์ƒ์„ฑ: 2026-09-03 02:51:46 (rule)_ + +## AI ์ฝ”๋ฉ˜ํŠธ (์ด์ „ ์žฅ / ์•ž์œผ๋กœ ์žฅ) [gemini] + +## ์ด์ „ ์žฅ์—์„œ๋Š” +์ด์ „ ์‹ค๋งค๋Š” 6๊ฑด ์Šน๋ฅ  67%์— -9,520์› ์†์‹ค์ž…๋‹ˆ๋‹ค. ๋ฐฑํ…Œ์ŠคํŠธ Optuna๋Š” ํƒ์ƒ‰/์‚ฌํ›„ํ•ฉ๊ฒฉ ๋ชจ๋‘ 0๊ฑด์œผ๋กœ, **์œ ์˜๋ฏธํ•œ ์ „๋žต์ด ์ „๋ฌดํ–ˆ์Šต๋‹ˆ๋‹ค.** 5์ผ ๊ธฐ๊ฐ„์€ ํ‘œ๋ณธ ๋ถ€์กฑ ์œ„ํ—˜์ด ํฌ๋ฉฐ, ์‹ค๋งค-๋ฐฑํ…Œ ๊ดด๋ฆฌ(๊ณ ์ŠคํŠธ ํผ์ง€)๋Š” ๋Š˜ ์กด์žฌํ•ฉ๋‹ˆ๋‹ค. + +## ์•ž์œผ๋กœ ์žฅ์—์„œ๋Š” +์‚ฌํ›„ํ•ฉ๊ฒฉ ์ „๋žต์ด ์—†์œผ๋ฏ€๋กœ **ํ˜„ํ–‰ DB ์œ ์ง€ ๋ฐ ์œ ๋‹ˆ๋ฒ„์Šคยท๋ฐ์ดํ„ฐ ์žฌ๊ฒ€์ฆ์ด ์šฐ์„ ์ž…๋‹ˆ๋‹ค.** ๋‹จ๊ธฐ Optuna ๊ฒฐ๊ณผ๋Š” ๊ณผ์ ํ•ฉยทํ‘œ๋ณธ ๋ถ€์กฑ ์œ„ํ—˜์ด ์ปค ์‹ค๋งค ์ ์šฉ์€ ์ ˆ๋Œ€ ๊ธˆ์ง€. `mode Top10 1์œ„`๋Š” ํ›„๋ณด์ผ ๋ฟ, **DB 1์ˆœ์œ„๋Š” ์‚ฌํ›„ํ•ฉ๊ฒฉ(gated)์ž…๋‹ˆ๋‹ค.** ๋ฐฑํ…Œ์ŠคํŠธ์™€ ์‹ค๋งค ๊ดด๋ฆฌ(๊ณ ์ŠคํŠธ ํผ์ง€)๋ฅผ ๋ถ„๋ช…ํžˆ ๊ฒฝ๊ณ ํ•ฉ๋‹ˆ๋‹ค. diff --git a/kis_trader/backtest/results/optuna_tail_tpe_20260903_025917.briefing.md b/kis_trader/backtest/results/optuna_tail_tpe_20260903_025917.briefing.md new file mode 100644 index 0000000..e1c192a --- /dev/null +++ b/kis_trader/backtest/results/optuna_tail_tpe_20260903_025917.briefing.md @@ -0,0 +1,51 @@ +# Optuna ๋ธŒ๋ฆฌํ•‘ โ€” ๊ผฌ๋ฆฌ (tpe) +๊ธฐ๊ฐ„: 2026-08-24 ~ 2026-08-28 (๊ฑฐ๋ž˜์ผโ‰ˆ5์ผ) ยท trials 200/200 +ํƒ์ƒ‰ ๊ฒŒ์ดํŠธ: WRโ‰ฅ0% PFโ‰ฅ0 ยท min_tradesโ‰ฅ1 | ํ›„๋ณด ๊ฒŒ์ดํŠธ: WRโ‰ฅ40% PFโ‰ฅ1 ยท min_tradesโ‰ฅ1 +- min_trades=1: **ํ•ฉ๊ฒฉ ์ธ์ • ์ตœ์†Œ ๊ฑฐ๋ž˜ ๊ฑด์ˆ˜**(ํ‘œ๋ณธ ๋ถ€์กฑยท์šฐ์—ฐ ์Šน๋ฅ  ๋ฐฉ์ง€). ์ด๋ณด๋‹ค ์ ์€ ์กฐํ•ฉ์€ ํ•™์Šต/ํ›„๋ณด ์ง‘๊ณ„์—์„œ ์ œ์™ธ๋ฉ๋‹ˆ๋‹ค. +ํ•™์Šต์šฉ ํ†ต๊ณผ 0๊ฑด ยท ์‚ฌํ›„ํ•ฉ๊ฒฉ(results_gated) 0๊ฑด + +## ๊ณผ์ ํ•ฉยท์ ์šฉ ๊ฐ€๋Šฅ๋„ (ํœด๋ฆฌ์Šคํ‹ฑ) +- **๊ณผ์ ํ•ฉ ์œ„ํ—˜ 33.0%** ยท **์ ์šฉ ๊ฐ€๋Šฅ๋„ 67.0%** ยท ํŒ์ •: **์ƒ๋Œ€์ ์œผ๋กœ๋‚ฎ์Œ** โ€” ํœด๋ฆฌ์Šคํ‹ฑ์ƒ ์œ„ํ—˜ ์ƒ๋Œ€์  ๋‚ฎ์Œ โ€” ๊ทธ๋ž˜๋„ ๋‹ค์ผ ํ™•์ธ ๊ถŒ์žฅ + - ํ‘œ๋ณธ ์žฅ์ผ: +0.0p โ€” ๊ฑฐ๋ž˜์ผโ‰ˆ5์ผ โ€” ํ‘œ๋ณธ ์ผ์ˆ˜ ์ƒ๋Œ€์  ์–‘ํ˜ธ + - ๊ฑฐ๋ž˜ ํ‘œ๋ณธ: +25.0p โ€” ํ†ต๊ณผ ํ›„๋ณด ์—†์Œ โ€” ์ ์šฉ ๋ถˆ๊ฐ€ + - ์Šน๋ฅ ยทPF ์ด์ƒ์น˜: +0.0p โ€” ์ด์ƒ์น˜ ์—†์Œ + - ๊ฒŒ์ดํŠธ ์ปค๋ฒ„: +8.0p โ€” ํ•™์Šตยทgated ๋ชจ๋‘ ๋น„์–ด ์žˆ์Œ + - PnL ๊ณ ์›: +0.0p โ€” ๊ณ ์› ํŒ์ • ์Šคํ‚ต +- _์ฐธ๊ณ : ๊ณผ์ ํ•ฉ%๋Š” ๊ต์ฐจ๊ฒ€์ฆ ์ ์ˆ˜๊ฐ€ ์•„๋‹ˆ๋ผ ํ‘œ๋ณธยท์ด์ƒ์น˜ยท๊ณ ์› ํœด๋ฆฌ์Šคํ‹ฑ์ž…๋‹ˆ๋‹ค. ์ ์šฉ ๊ฐ€๋Šฅ๋„%=100โˆ’๊ณผ์ ํ•ฉ์œ„ํ—˜%. DB ์ ์šฉ ๋ฒ„ํŠผ ํ™œ์„ฑ ์กฐ๊ฑด(gated PnL>0)๊ณผ๋Š” ๋ณ„๊ฐœ์ž…๋‹ˆ๋‹ค._ + +## ์ตœ์ข… ์„ ํƒ ํ›„๋ณด (๊ทœ์น™ ยท DB ์ ์šฉ ์ „ ํ™•์ธ) +- ์•„๋ž˜๋Š” **์—ญํ• ์ด ๋‹ค๋ฅธ** 4์ข… ํ›„๋ณด์ž…๋‹ˆ๋‹ค. mode Top10 1์œ„ โ‰  ์ต์ ˆ ๋Œ€ํ‘œ ยท **DB 1์ˆœ์œ„๋Š” ์‚ฌํ›„ํ•ฉ๊ฒฉ(gated)** ์ž…๋‹ˆ๋‹ค. +- mode pool: `positive` ยท scoring: `band_proximity_p25_p75` + +### ํ›„๋ณด 4์ข… +- **โ‘  ์‚ฌํ›„ํ•ฉ๊ฒฉ 1์œ„ (apply: gated)**: ์—†์Œ +- **โ‘ก ์•ˆ์ • 1์œ„ (apply: stable)**: ์—†์Œ +- **โ‘ข mode_combo (apply: mode)**: ์—†์Œ (๋ฏธ์‚ฐ์ถœยท๊ตฌ JSON) +- **โ‘ฃ mode Top10 1์œ„ (apply: consensus ยท ๋ฐด๋“œ ์ „ํ˜• trial)**: ์—†์Œ +- mode Top10 meta: pool 0๊ฑด ยท ์ถ• 0๊ฐœ + +### ์ถ”์ฒœ (์ž๋™ ยท confirm ํ•„์ˆ˜) +1. **์‚ฌํ›„ํ•ฉ๊ฒฉ 0๊ฑด โ†’ DB ์ ์šฉ ๋น„๊ถŒ์žฅ.** ํ˜„ํ–‰ DB ์œ ์ง€ + ์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑยท๊ธฐ๊ฐ„ ์žฌ๊ฒ€์ฆ. +- โš  ์•ˆ์ • ๊ฒŒ์ดํŠธ 0๊ฑด โ†’ ์•ˆ์ • Top์€ **์ ์ˆ˜์ˆœ ํด๋ฐฑ** (์•ˆ์ • ๊ฒŒ์ดํŠธ 0๊ฑด โ†’ ํ•™์Šตํ’€ ์•ˆ์ •์ ์ˆ˜์ˆœ TopN (๋งˆ์ด๋„ˆ์Šค PnL ํฌํ•จ ยท ์ƒ๋Œ€๋น„๊ต)) + +## ์ด์ „ ์žฅ์—์„œ๋Š” +- ์‹ค๋งค ๋™๊ธฐ๊ฐ„ ์ฒญ์‚ฐ 6๊ฑด ยท ์Šน๋ฅ  67% ยท ํ•ฉ์‚ฐ PnL -9,520์› (๋ฐฑํ…Œ Optuna์™€ ์ˆซ์ž ๋‹ฌ๋ผ๋„ ์ •์ƒ โ€” ๊ณ ์ŠคํŠธยท์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑ ๊ฒฝ๋กœ ์ฐจ์ด). +- ์ด ๊ธฐ๊ฐ„ ๋ฐฑํ…Œ์—์„œ๋Š” **์œ ์˜๋ฏธํ•œ ํ†ต๊ณผ ์กฐํ•ฉ์ด ๊ฑฐ์˜ ์—†์—ˆ์Šต๋‹ˆ๋‹ค.** ์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑยท์†์ ˆยท์‹œ๊ฐ„์ฐฝ์„ ๋จผ์ € ์ ๊ฒ€ํ•˜์„ธ์š” (๋ŒํŒŒ 0๊ฑด์ด๋ฉด ํŠนํžˆ). + +## ์•ž์œผ๋กœ ์žฅ์—์„œ๋Š” +- **1~2์ผ Optuna best๋ฅผ ๋ฐ”๋กœ ์‹ค๋งค์— ๋„ฃ์ง€ ๋งˆ์„ธ์š”.** ๋‹ค์ผ(โ‰ฅ5๊ฑฐ๋ž˜์ผ) ์žฌ๊ฒ€์ฆยท์›น๋ฐฑํ…Œ 1ํšŒ ํ›„ ๊ฒ€ํ† . +- ์ ์šฉ ์‹œ์—๋Š” `results_gated` ํ›„๋ณด๋งŒ. ํƒ์ƒ‰์šฉ best(objective)์™€ ๋‹ค๋ฅผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. +- ์žฅ์ด ์ข์•„์ง€๊ฑฐ๋‚˜ ๋ณ€๋™์„ฑ์ด ์ปค์ง€๋ฉด: ์†์ ˆยทํŠธ๋ ˆ์ผยท์‹œ๊ฐ„์ฐฝ์ด ๋จผ์ € ๊นจ์ง‘๋‹ˆ๋‹ค. ์Šน๋ฅ  ์ž๋ž‘๋ณด๋‹ค **์†์ ˆ์ด ์‚ด์•„ ์žˆ๋Š”์ง€**๋ฅผ ๋ณด์„ธ์š”. +- ํ˜„์žฌ ์‚ฌํ›„ํ•ฉ๊ฒฉ 0๊ฑด โ†’ ํŒŒ๋ผ๋ฏธํ„ฐ ์œ ์ง€(ํ˜„ํ–‰ DB) + ์œ ๋‹ˆ๋ฒ„์Šค/๋ฐ์ดํ„ฐ ์ ๊ฒ€์ด ์šฐ์„ ์ž…๋‹ˆ๋‹ค. + +_์ƒ์„ฑ: 2026-09-03 02:59:17 (rule)_ + +## AI ์ฝ”๋ฉ˜ํŠธ (์ด์ „ ์žฅ / ์•ž์œผ๋กœ ์žฅ) [gemini] + +## ์ด์ „ ์žฅ์—์„œ๋Š” + +์ด์ „ 5๊ฑฐ๋ž˜์ผ(2026-08-24 ~ 2026-08-28) ์‹ค์ œ ๋งค๋งค๋Š” 6๊ฑด ์ฒญ์‚ฐ, ์Šน๋ฅ  67%๋กœ -9,520์› ์†์‹ค์„ ๊ธฐ๋กํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š” ๋ฐฑํ…Œ์ŠคํŠธ์™€ ์‹ค๋งค ๊ฐ„์˜ ์ž์—ฐ์Šค๋Ÿฌ์šด ๊ดด๋ฆฌ(๊ณ ์ŠคํŠธํผ์ง€ ๋“ฑ)๊ฐ€ ์กด์žฌํ•จ์„ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค. ๋” ์ค‘์š”ํ•œ ๊ฒƒ์€ Optuna ๋ฐฑํ…Œ์ŠคํŠธ ๊ฒฐ๊ณผ, **์—„๊ฒฉํ•œ ๊ธฐ์ค€์„ ํ†ต๊ณผํ•œ ์œ ์˜๋ฏธํ•œ ์ „๋žต ์กฐํ•ฉ์ด ๋‹จ ํ•œ ๊ฑด๋„ ์—†์—ˆ๋‹ค๋Š” ์ **์ž…๋‹ˆ๋‹ค. ์ด๋Š” **๊ทน์‹ฌํ•œ ํ‘œ๋ณธ ๋ถ€์กฑ๊ณผ ๊ณผ์ ํ•ฉ ์œ„ํ—˜**์„ ๊ฐ•๋ ฅํžˆ ๊ฒฝ๊ณ ํ•˜๋ฉฐ, ํ˜„์žฌ ์ „๋žต์ด ํ•ด๋‹น ๊ธฐ๊ฐ„ ์‹œ์žฅ์— ๋ถ€์ ํ•ฉํ–ˆ์Œ์„ ๋ช…ํ™•ํžˆ ์‹œ์‚ฌํ•ฉ๋‹ˆ๋‹ค. + +## ์•ž์œผ๋กœ ์žฅ์—์„œ๋Š” + +์‚ฌํ›„ํ•ฉ๊ฒฉ(gated)๋œ ์ „๋žต์ด ์ „๋ฌดํ•˜๋ฏ€๋กœ, **์ ˆ๋Œ€๋กœ ํ˜„์žฌ Optuna ๊ฒฐ๊ณผ๋ฅผ ์‹ค๋งค์— ์ ์šฉํ•ด์„œ๋Š” ์•ˆ ๋ฉ๋‹ˆ๋‹ค.** 5๊ฑฐ๋ž˜์ผ์ด๋ผ๋Š” ์งง์€ ํ‘œ๋ณธ์€ **๊ณผ์ ํ•ฉ ์œ„ํ—˜์ด ๊ทน๋„๋กœ ๋†’์œผ๋ฉฐ, ํ‘œ๋ณธ ๋ถ€์กฑ์œผ๋กœ ์ธํ•œ ์šฐ์—ฐํ•œ ๊ฒฐ๊ณผ์ผ ๊ฐ€๋Šฅ์„ฑ์ด ํฝ๋‹ˆ๋‹ค.** `mode Top10 1์œ„`์™€ ๊ฐ™์€ ํƒ์ƒ‰ ๊ฒฐ๊ณผ๋Š” **์ต์ ˆ ๋Œ€ํ‘œ๊ฐ€ ์•„๋‹ˆ๋ฉฐ, DB 1์ˆœ์œ„๋Š” ์˜ค์ง ์‚ฌํ›„ํ•ฉ๊ฒฉ๋œ ์ „๋žต๋ฟ**์ž„์„ ๋ช…์‹ฌํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์‹ค๋งค ์ ์šฉ ์ „์—๋Š” ์œ ๋‹ˆ๋ฒ„์Šค, ํ‹ฑ ๋ฐ์ดํ„ฐ, ์†์ ˆ ๊ธฐ์ค€, ๊ทธ๋ฆฌ๊ณ  ๋ฐฑํ…Œ์ŠคํŠธ ๊ธฐ๊ฐ„์„ ํ›จ์”ฌ ๊ธธ๊ฒŒ **์žฌ๊ฒ€์ฆํ•˜์—ฌ ๋ฐฑํ…Œ์ŠคํŠธ-์‹ค๋งค ๊ดด๋ฆฌ(๊ณ ์ŠคํŠธํผ์ง€ ๋“ฑ)๋ฅผ ์ตœ์†Œํ™”ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.** ํ™•์ •์ ์ธ ์ˆ˜์ต์„ ์•ฝ์†ํ•˜๊ฑฐ๋‚˜ ํŠน์ • ์ข…๋ชฉ ๋งค์ˆ˜๋ฅผ ์ถ”์ฒœํ•˜๋Š” ๊ฒƒ์€ ๋ถˆ๊ฐ€๋Šฅํ•˜๋ฉฐ, ํ˜„ํ–‰ DB ์œ ์ง€์™€ ๋ฐ์ดํ„ฐ ์ ๊ฒ€์ด ์šฐ์„ ์ž…๋‹ˆ๋‹ค. diff --git a/kis_trader/backtest/results/optuna_tail_tpe_20260903_084001.briefing.md b/kis_trader/backtest/results/optuna_tail_tpe_20260903_084001.briefing.md new file mode 100644 index 0000000..a9ceefa --- /dev/null +++ b/kis_trader/backtest/results/optuna_tail_tpe_20260903_084001.briefing.md @@ -0,0 +1,67 @@ +# Optuna ๋ธŒ๋ฆฌํ•‘ โ€” ๊ผฌ๋ฆฌ (tpe) +๊ธฐ๊ฐ„: 2026-08-24 ~ 2026-08-28 (๊ฑฐ๋ž˜์ผโ‰ˆ5์ผ) ยท trials 200/200 +ํƒ์ƒ‰ ๊ฒŒ์ดํŠธ: WRโ‰ฅ0% PFโ‰ฅ0 ยท min_tradesโ‰ฅ1 | ํ›„๋ณด ๊ฒŒ์ดํŠธ: WRโ‰ฅ40% PFโ‰ฅ1 ยท min_tradesโ‰ฅ1 +- min_trades=1: **ํ•ฉ๊ฒฉ ์ธ์ • ์ตœ์†Œ ๊ฑฐ๋ž˜ ๊ฑด์ˆ˜**(ํ‘œ๋ณธ ๋ถ€์กฑยท์šฐ์—ฐ ์Šน๋ฅ  ๋ฐฉ์ง€). ์ด๋ณด๋‹ค ์ ์€ ์กฐํ•ฉ์€ ํ•™์Šต/ํ›„๋ณด ์ง‘๊ณ„์—์„œ ์ œ์™ธ๋ฉ๋‹ˆ๋‹ค. +ํ•™์Šต์šฉ ํ†ต๊ณผ 95๊ฑด ยท ์‚ฌํ›„ํ•ฉ๊ฒฉ(results_gated) 93๊ฑด + +## ๊ณผ์ ํ•ฉยท์ ์šฉ ๊ฐ€๋Šฅ๋„ (ํœด๋ฆฌ์Šคํ‹ฑ) +- **๊ณผ์ ํ•ฉ ์œ„ํ—˜ 43.0%** ยท **์ ์šฉ ๊ฐ€๋Šฅ๋„ 57.0%** ยท ํŒ์ •: **์ฃผ์˜** โ€” ์ ์šฉ ๊ฐ€๋Šฅ๋„ ์ค‘๊ฐ„ โ€” ๋‹ค์ผ(โ‰ฅ5์ผ) ์žฌ๊ฒ€์ฆยท์›น๋ฐฑํ…Œ ํ›„ ์†Œ์•ก๋งŒ + - ํ‘œ๋ณธ ์žฅ์ผ: +0.0p โ€” ๊ฑฐ๋ž˜์ผโ‰ˆ5์ผ โ€” ํ‘œ๋ณธ ์ผ์ˆ˜ ์ƒ๋Œ€์  ์–‘ํ˜ธ + - ๊ฑฐ๋ž˜ ํ‘œ๋ณธ: +18.0p โ€” ์ƒ์œ„ ํ›„๋ณด ๊ฑฐ๋ž˜ 2๊ฑด โ€” ํ‘œ๋ณธ ๋ถ€์กฑ + - ์Šน๋ฅ ยทPF ์ด์ƒ์น˜: +25.0p โ€” ์Šน๋ฅ  100.0% + ๊ฑฐ๋ž˜ 2๊ฑด ยท PF 9999.00 (์†Œ์ˆ˜ ๊ฑฐ๋ž˜ ํญ์ฆ) + - ๊ฒŒ์ดํŠธ ์ปค๋ฒ„: +0.0p โ€” ์‚ฌํ›„ํ•ฉ๊ฒฉ 93๊ฑด ยท stable 3๊ฑด + - PnL ๊ณ ์›: +0.0p โ€” ๊ณ ์› ๋น„์œจ 5% (5๊ฑด) +- ์ž„๊ณ„๊ฐ’ ๋ถ„ํฌ ํ‘œ๋ณธ: results_gated ์ƒ์œ„ 30๊ฑด +| ํŒŒ๋ผ๋ฏธํ„ฐ | median | p25~p75 | mode(๋น„์œจ) | +|---|---:|---|---| +| `entry_mode` | โ€” | โ€” | align (100%) | +| `cand_limit` | 0.0 | 0.0 ~ 20.0 | 0 (53%) | +| `max_daily_change` | 33.5 | 29.0 ~ 40.75 | 32.0 (13%) | +| `min_drop_rate` | 0.035 | 0.01125 ~ 0.04375 | 0.045 (17%) | +| `min_recovery_ratio` | 0.11 | 0.1 ~ 0.1475 | 0.1 (20%) | +| `tail_ratio_min` | 1.1 | 0.825 ~ 1.2 | 1.2 (20%) | +| `tail_pct_min` | 0.00825 | 0.007125 ~ 0.009 | 0.0085 (20%) | +| `max_rec_3m` | 0.89 | 0.8525 ~ 0.91 | 0.9 (13%) | +| `shoulder_min_high` | 0.004 | 0.003 ~ 0.00675 | 0.003 (27%) | +| `shoulder_cut_pct` | 0.003 | 0.002 ~ 0.004 | 0.0015 (17%) | +| `stop_atr_mult` | 2.65 | 2.2 ~ 2.9 | 2.9 (23%) | +| `target_atr_mult` | 1.35 | 1.0 ~ 2.1 | 0.8 (13%) | +- _์ฐธ๊ณ : ๊ณผ์ ํ•ฉ%๋Š” ๊ต์ฐจ๊ฒ€์ฆ ์ ์ˆ˜๊ฐ€ ์•„๋‹ˆ๋ผ ํ‘œ๋ณธยท์ด์ƒ์น˜ยท๊ณ ์› ํœด๋ฆฌ์Šคํ‹ฑ์ž…๋‹ˆ๋‹ค. ์ ์šฉ ๊ฐ€๋Šฅ๋„%=100โˆ’๊ณผ์ ํ•ฉ์œ„ํ—˜%. DB ์ ์šฉ ๋ฒ„ํŠผ ํ™œ์„ฑ ์กฐ๊ฑด(gated PnL>0)๊ณผ๋Š” ๋ณ„๊ฐœ์ž…๋‹ˆ๋‹ค._ + +## ์ตœ์ข… ์„ ํƒ ํ›„๋ณด (๊ทœ์น™ ยท DB ์ ์šฉ ์ „ ํ™•์ธ) +- ์•„๋ž˜๋Š” **์—ญํ• ์ด ๋‹ค๋ฅธ** 4์ข… ํ›„๋ณด์ž…๋‹ˆ๋‹ค. mode Top10 1์œ„ โ‰  ์ต์ ˆ ๋Œ€ํ‘œ ยท **DB 1์ˆœ์œ„๋Š” ์‚ฌํ›„ํ•ฉ๊ฒฉ(gated)** ์ž…๋‹ˆ๋‹ค. +- mode pool: `positive` ยท scoring: `band_proximity_p25_p75` + +### ํ›„๋ณด 4์ข… +- **โ‘  ์‚ฌํ›„ํ•ฉ๊ฒฉ 1์œ„ (apply: gated)** (trial #99): PnL 6,410์› ยท WR 100.0% ยท PF 9999.00 ยท ๊ฑฐ๋ž˜ 2๊ฑด ยท ์•ˆ์ •์ ์ˆ˜ 6410 ยท ํ˜ธ๊ฐ€OFF ยท ํœฉ์˜ON sub45s lb180s dip0.50% tol0.05% +- **โ‘ก ์•ˆ์ • 1์œ„ (apply: stable)** (trial #74): PnL 3,978์› ยท WR 50.0% ยท PF 4.94 ยท ๊ฑฐ๋ž˜ 2๊ฑด ยท ์•ˆ์ •์ ์ˆ˜ -1010 ยท ํ˜ธ๊ฐ€OFF ยท ํœฉ์˜ON sub60s lb180s dip0.40% tol0.15% +- **โ‘ข mode_combo (apply: mode)** (trial ์—†์Œ(์กฐ๋ฆฝ)): PnL 4,988์› ยท WR 100.0% ยท PF 9999.00 ยท ๊ฑฐ๋ž˜ 1๊ฑด ยท ์•ˆ์ •์ ์ˆ˜ 4988 ยท ํ˜ธ๊ฐ€OFF ยท ํœฉ์˜ON sub45s lb180s dip0.50% tol0.05% +- **โ‘ฃ mode Top10 1์œ„ (apply: consensus ยท ๋ฐด๋“œ ์ „ํ˜• trial)** (trial #29): PnL 4,988์› ยท WR 100.0% ยท PF 9999.00 ยท ๊ฑฐ๋ž˜ 1๊ฑด ยท ์•ˆ์ •์ ์ˆ˜ 4988 ยท ๊ทผ์ ‘ 97.6% (44/52์ถ• ๋ฐด๋“œ์•ˆ) ยท ํ˜ธ๊ฐ€OFF ยท ํœฉ์˜ON sub45s lb180s dip0.50% tol0.10% +- mode Top10 meta: pool 94๊ฑด ยท ์ถ• 52๊ฐœ + +### ์ถ”์ฒœ (์ž๋™ ยท confirm ํ•„์ˆ˜) +1. **์‹ค๋งค DB ์ ์šฉ 1์ˆœ์œ„ โ†’ โ‘  ์‚ฌํ›„ํ•ฉ๊ฒฉ 1์œ„** (`optunaApply gated`) โ€” WR/PFยทmin_trades ์‚ฌํ›„ ํ†ต๊ณผ. +2. **๋ณ€๋™์„ฑยท์†์‹ค์ผ ์ค„์ด๊ธฐ โ†’ โ‘ก ์•ˆ์ • 1์œ„** (`stable`) โ€” PnL๋ณด๋‹ค ์ผ๋ณ„ ์•ˆ์ • ์šฐ์„  ์‹œ. +3. **2์ฐจ narrowยท๋Œ€ํ‘œ ์ˆซ์ž โ†’ โ‘ข mode_combo** โ€” ์ถ•๋ณ„ ์ตœ๋นˆ ์กฐ๋ฆฝ ยท trial ๋ฒˆํ˜ธ ์—†์Œ ยท ์ต์ ˆ์€ pool ์ตœ๋นˆ๊ฐ’ ์ฐธ๊ณ . +4. **โ‘ฃ mode Top10 1์œ„** โ€” ์–‘์ˆ˜ pool ์ „ํ˜• trial(๋‹ค์ถ• ๋ฐด๋“œ ๊ทผ์ ‘). **์ต์ ˆ ํ•˜๋‚˜๋กœ ์“ฐ์ง€ ๋ง ๊ฒƒ** ยท ํ‘œ์—์„œ ใ€Œ๋ณด๊ธฐใ€โ†’ consensus apply. + +## ์ด์ „ ์žฅ์—์„œ๋Š” +- ์‹ค๋งค ๋™๊ธฐ๊ฐ„ ์ฒญ์‚ฐ 6๊ฑด ยท ์Šน๋ฅ  67% ยท ํ•ฉ์‚ฐ PnL -9,520์› (๋ฐฑํ…Œ Optuna์™€ ์ˆซ์ž ๋‹ฌ๋ผ๋„ ์ •์ƒ โ€” ๊ณ ์ŠคํŠธยท์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑ ๊ฒฝ๋กœ ์ฐจ์ด). +- ์‚ฌํ›„ํ•ฉ๊ฒฉ 1์œ„: trial #99 ยท ๊ฑฐ๋ž˜ 2๊ฑด ยท ์Šน๋ฅ  100.0% ยท PF 9999.00 ยท PnL 6,410์› +- ์Šน๋ฅ ์ด ๋น„์ •์ƒ์ ์œผ๋กœ ๋†’๊ณ  ํ‘œ๋ณธ์ด ์ž‘์Šต๋‹ˆ๋‹ค โ†’ **ํ•ด๋‹น ์žฅ์—๋งŒ ๋งž๋Š” ๊ณผ์ ํ•ฉ** ์‹ ํ˜ธ. + +## ์•ž์œผ๋กœ ์žฅ์—์„œ๋Š” +- **1~2์ผ Optuna best๋ฅผ ๋ฐ”๋กœ ์‹ค๋งค์— ๋„ฃ์ง€ ๋งˆ์„ธ์š”.** ๋‹ค์ผ(โ‰ฅ5๊ฑฐ๋ž˜์ผ) ์žฌ๊ฒ€์ฆยท์›น๋ฐฑํ…Œ 1ํšŒ ํ›„ ๊ฒ€ํ† . +- ์ ์šฉ ์‹œ์—๋Š” `results_gated` ํ›„๋ณด๋งŒ. ํƒ์ƒ‰์šฉ best(objective)์™€ ๋‹ค๋ฅผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. +- ์žฅ์ด ์ข์•„์ง€๊ฑฐ๋‚˜ ๋ณ€๋™์„ฑ์ด ์ปค์ง€๋ฉด: ์†์ ˆยทํŠธ๋ ˆ์ผยท์‹œ๊ฐ„์ฐฝ์ด ๋จผ์ € ๊นจ์ง‘๋‹ˆ๋‹ค. ์Šน๋ฅ  ์ž๋ž‘๋ณด๋‹ค **์†์ ˆ์ด ์‚ด์•„ ์žˆ๋Š”์ง€**๋ฅผ ๋ณด์„ธ์š”. +- ์‚ฌํ›„ํ•ฉ๊ฒฉ์ด ์žˆ์–ด๋„ โ€˜๋‚ด์ผ๋„ ๊ฐ™์€ ์žฅโ€™์ด ์•„๋‹™๋‹ˆ๋‹ค. ํŽ˜์ดํผ/์†Œ์•กยท๋ชจ์˜๋กœ 1~2์ผ ๊ด€์ฐฐ ํ›„ ํ™•๋Œ€ํ•˜์„ธ์š”. + +_์ƒ์„ฑ: 2026-09-03 08:40:05 (rule)_ + +## AI ์ฝ”๋ฉ˜ํŠธ (์ด์ „ ์žฅ / ์•ž์œผ๋กœ ์žฅ) [gemini] + +## ์ด์ „ ์žฅ์—์„œ๋Š” +์ง€๋‚œ 5๊ฑฐ๋ž˜์ผ ๊ฐ„ ์‹ค๋งค ์ฒญ์‚ฐ PnL์€ -9,520์›์œผ๋กœ ๋ฐฑํ…Œ์ŠคํŠธ์™€ ํฐ ๊ดด๋ฆฌ๋ฅผ ๋ณด์˜€์Šต๋‹ˆ๋‹ค. Optuna ์‚ฌํ›„ํ•ฉ๊ฒฉ 1์œ„๋Š” 2๊ฑด ๊ฑฐ๋ž˜์— ์Šน๋ฅ  100%, PF 9999.00์„ ๊ธฐ๋กํ–ˆ์œผ๋‚˜, ์ด๋Š” **๊ทนํžˆ ์งง์€ ๊ธฐ๊ฐ„๊ณผ ์ ์€ ๊ฑฐ๋ž˜๋Ÿ‰(2๊ฑด)**์œผ๋กœ ์ธํ•œ **๋ช…๋ฐฑํ•œ ๊ณผ์ ํ•ฉ** ์‹ ํ˜ธ์ž…๋‹ˆ๋‹ค. **๊ณผ์ ํ•ฉ ์œ„ํ—˜ 43.0%** `์ฃผ์˜` ํŒ์ •์ด ๋‚˜์™”๋“ฏ, ํ‘œ๋ณธ ๋ถ€์กฑ๊ณผ ์šฐ์—ฐํ•œ ์Šน๋ฅ ์— ๋งค์šฐ ์ทจ์•ฝํ•œ ๊ฒฐ๊ณผ์ž…๋‹ˆ๋‹ค. + +## ์•ž์œผ๋กœ ์žฅ์—์„œ๋Š” +**์งง์€ ๊ธฐ๊ฐ„์˜ ๋ฐฑํ…Œ์ŠคํŠธ ๊ฒฐ๊ณผ๋Š” ๊ณผ์ ํ•ฉ ์œ„ํ—˜์ด ๋งค์šฐ ๋†’์œผ๋ฏ€๋กœ** ์ฆ‰์‹œ ์‹ค๋งค์— ์ ์šฉํ•˜๋Š” ๊ฒƒ์€ ์œ„ํ—˜ํ•ฉ๋‹ˆ๋‹ค. ๋ฐฑํ…Œ์ŠคํŠธ ์ƒ์˜ **๋†’์€ ์Šน๋ฅ ๊ณผ PF๋Š” ์†Œ์ˆ˜ ๊ฑฐ๋ž˜์—์„œ ๋ฐœ์ƒํ•œ ์šฐ์—ฐ์ผ ๊ฐ€๋Šฅ์„ฑ์ด ํฌ๋ฉฐ**, ์‹ค์ œ ์‹œ์žฅ์—์„œ๋Š” **๊ณ ์ŠคํŠธํผ์ง€ ํ˜„์ƒ** ๋“ฑ์œผ๋กœ ๋ฐฑํ…Œ์ŠคํŠธ์™€ ๋‹ค๋ฅธ ๊ดด๋ฆฌ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. `mode Top10 1์œ„`๋ฅผ ์ต์ ˆ ๋Œ€ํ‘œ๋กœ ๋‹จ์ •ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ์‹ค๋งค ์ ์šฉ ์ „ ๋ฐ˜๋“œ์‹œ **๋‹ค์ผ ์žฌ๊ฒ€์ฆ, ์›น๋ฐฑํ…Œ์ŠคํŠธ ๋ฐ ์†Œ์•ก ๋ชจ์˜ ํˆฌ์ž๋ฅผ ํ†ตํ•ด ์†์‹ค ๊ด€๋ฆฌ ์œ ํšจ์„ฑ์„ ์ถฉ๋ถ„ํžˆ ๊ฒ€์ฆ**ํ•œ ํ›„ ์‹ ์ค‘ํ•˜๊ฒŒ ์ ‘๊ทผํ•˜์„ธ์š”. ํŠน์ • ์ข…๋ชฉ ๋งค์ˆ˜ ์ถ”์ฒœ์ด๋‚˜ ํ™•์ • ์ˆ˜์ต์€ ์•ฝ์†ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. diff --git a/kis_trader/backtest/results/optuna_tail_tpe_20260903_084735.briefing.md b/kis_trader/backtest/results/optuna_tail_tpe_20260903_084735.briefing.md new file mode 100644 index 0000000..fe4a71f --- /dev/null +++ b/kis_trader/backtest/results/optuna_tail_tpe_20260903_084735.briefing.md @@ -0,0 +1,69 @@ +# Optuna ๋ธŒ๋ฆฌํ•‘ โ€” ๊ผฌ๋ฆฌ (tpe) +๊ธฐ๊ฐ„: 2026-08-24 ~ 2026-08-28 (๊ฑฐ๋ž˜์ผโ‰ˆ5์ผ) ยท trials 200/200 +ํƒ์ƒ‰ ๊ฒŒ์ดํŠธ: WRโ‰ฅ0% PFโ‰ฅ0 ยท min_tradesโ‰ฅ1 | ํ›„๋ณด ๊ฒŒ์ดํŠธ: WRโ‰ฅ40% PFโ‰ฅ1 ยท min_tradesโ‰ฅ1 +- min_trades=1: **ํ•ฉ๊ฒฉ ์ธ์ • ์ตœ์†Œ ๊ฑฐ๋ž˜ ๊ฑด์ˆ˜**(ํ‘œ๋ณธ ๋ถ€์กฑยท์šฐ์—ฐ ์Šน๋ฅ  ๋ฐฉ์ง€). ์ด๋ณด๋‹ค ์ ์€ ์กฐํ•ฉ์€ ํ•™์Šต/ํ›„๋ณด ์ง‘๊ณ„์—์„œ ์ œ์™ธ๋ฉ๋‹ˆ๋‹ค. +ํ•™์Šต์šฉ ํ†ต๊ณผ 92๊ฑด ยท ์‚ฌํ›„ํ•ฉ๊ฒฉ(results_gated) 85๊ฑด + +## ๊ณผ์ ํ•ฉยท์ ์šฉ ๊ฐ€๋Šฅ๋„ (ํœด๋ฆฌ์Šคํ‹ฑ) +- **๊ณผ์ ํ•ฉ ์œ„ํ—˜ 43.0%** ยท **์ ์šฉ ๊ฐ€๋Šฅ๋„ 57.0%** ยท ํŒ์ •: **์ฃผ์˜** โ€” ์ ์šฉ ๊ฐ€๋Šฅ๋„ ์ค‘๊ฐ„ โ€” ๋‹ค์ผ(โ‰ฅ5์ผ) ์žฌ๊ฒ€์ฆยท์›น๋ฐฑํ…Œ ํ›„ ์†Œ์•ก๋งŒ + - ํ‘œ๋ณธ ์žฅ์ผ: +0.0p โ€” ๊ฑฐ๋ž˜์ผโ‰ˆ5์ผ โ€” ํ‘œ๋ณธ ์ผ์ˆ˜ ์ƒ๋Œ€์  ์–‘ํ˜ธ + - ๊ฑฐ๋ž˜ ํ‘œ๋ณธ: +18.0p โ€” ์ƒ์œ„ ํ›„๋ณด ๊ฑฐ๋ž˜ 3๊ฑด โ€” ํ‘œ๋ณธ ๋ถ€์กฑ + - ์Šน๋ฅ ยทPF ์ด์ƒ์น˜: +25.0p โ€” ์Šน๋ฅ  100.0% + ๊ฑฐ๋ž˜ 3๊ฑด ยท PF 9999.00 (์†Œ์ˆ˜ ๊ฑฐ๋ž˜ ํญ์ฆ) + - ๊ฒŒ์ดํŠธ ์ปค๋ฒ„: +0.0p โ€” ์‚ฌํ›„ํ•ฉ๊ฒฉ 85๊ฑด ยท stable 10๊ฑด + - PnL ๊ณ ์›: +0.0p โ€” ๊ณ ์› ๋น„์œจ 5% (4๊ฑด) +- ์ž„๊ณ„๊ฐ’ ๋ถ„ํฌ ํ‘œ๋ณธ: results_gated ์ƒ์œ„ 30๊ฑด +| ํŒŒ๋ผ๋ฏธํ„ฐ | median | p25~p75 | mode(๋น„์œจ) | +|---|---:|---|---| +| `entry_mode` | โ€” | โ€” | align (100%) | +| `cand_limit` | 0.0 | 0.0 ~ 0.0 | 0 (90%) | +| `max_daily_change` | 54.5 | 47.5 ~ 57.0 | 55.0 (13%) | +| `min_drop_rate` | 0.1025 | 0.05125 ~ 0.12375 | 0.115 (13%) | +| `min_recovery_ratio` | 0.135 | 0.0925 ~ 0.16 | 0.09 (17%) | +| `tail_ratio_min` | 1.1 | 0.9 ~ 1.2 | 1.2 (20%) | +| `tail_pct_min` | 0.00125 | 0.001 ~ 0.002 | 0.001 (30%) | +| `max_rec_3m` | 0.785 | 0.76 ~ 0.8275 | 0.76 (20%) | +| `shoulder_min_high` | 0.011 | 0.00725 ~ 0.013 | 0.014 (13%) | +| `shoulder_cut_pct` | 0.003 | 0.0025 ~ 0.003875 | 0.003 (27%) | +| `stop_atr_mult` | 1.4 | 1.1 ~ 1.8 | 1.3 (13%) | +| `target_atr_mult` | 3.1 | 2.525 ~ 3.375 | 3.4 (23%) | +- _์ฐธ๊ณ : ๊ณผ์ ํ•ฉ%๋Š” ๊ต์ฐจ๊ฒ€์ฆ ์ ์ˆ˜๊ฐ€ ์•„๋‹ˆ๋ผ ํ‘œ๋ณธยท์ด์ƒ์น˜ยท๊ณ ์› ํœด๋ฆฌ์Šคํ‹ฑ์ž…๋‹ˆ๋‹ค. ์ ์šฉ ๊ฐ€๋Šฅ๋„%=100โˆ’๊ณผ์ ํ•ฉ์œ„ํ—˜%. DB ์ ์šฉ ๋ฒ„ํŠผ ํ™œ์„ฑ ์กฐ๊ฑด(gated PnL>0)๊ณผ๋Š” ๋ณ„๊ฐœ์ž…๋‹ˆ๋‹ค._ + +## ์ตœ์ข… ์„ ํƒ ํ›„๋ณด (๊ทœ์น™ ยท DB ์ ์šฉ ์ „ ํ™•์ธ) +- ์•„๋ž˜๋Š” **์—ญํ• ์ด ๋‹ค๋ฅธ** 4์ข… ํ›„๋ณด์ž…๋‹ˆ๋‹ค. mode Top10 1์œ„ โ‰  ์ต์ ˆ ๋Œ€ํ‘œ ยท **DB 1์ˆœ์œ„๋Š” ์‚ฌํ›„ํ•ฉ๊ฒฉ(gated)** ์ž…๋‹ˆ๋‹ค. +- mode pool: `positive` ยท scoring: `band_proximity_p25_p75` + +### ํ›„๋ณด 4์ข… +- **โ‘  ์‚ฌํ›„ํ•ฉ๊ฒฉ 1์œ„ (apply: gated)** (trial #123): PnL 13,982์› ยท WR 100.0% ยท PF 9999.00 ยท ๊ฑฐ๋ž˜ 3๊ฑด ยท ์•ˆ์ •์ ์ˆ˜ 6352 ยท ํ˜ธ๊ฐ€OFF ยท ํœฉ์˜OFF +- **โ‘ก ์•ˆ์ • 1์œ„ (apply: stable)** (trial #123): PnL 13,982์› ยท WR 100.0% ยท PF 9999.00 ยท ๊ฑฐ๋ž˜ 3๊ฑด ยท ์•ˆ์ •์ ์ˆ˜ 6352 ยท ํ˜ธ๊ฐ€OFF ยท ํœฉ์˜OFF +- **โ‘ข mode_combo (apply: mode)** (trial ์—†์Œ(์กฐ๋ฆฝ)): PnL 3,702์› ยท WR 50.0% ยท PF 2.40 ยท ๊ฑฐ๋ž˜ 4๊ฑด ยท ์•ˆ์ •์ ์ˆ˜ -1608 ยท ํ˜ธ๊ฐ€OFF ยท ํœฉ์˜ON sub45s lb180s dip0.40% tol0.20% +- **โ‘ฃ mode Top10 1์œ„ (apply: consensus ยท ๋ฐด๋“œ ์ „ํ˜• trial)** (trial #129): PnL 5,310์› ยท WR 66.7% ยท PF 6.10 ยท ๊ฑฐ๋ž˜ 3๊ฑด ยท ์•ˆ์ •์ ์ˆ˜ 5310 ยท ๊ทผ์ ‘ 97.6% (44/52์ถ• ๋ฐด๋“œ์•ˆ) ยท ํ˜ธ๊ฐ€OFF ยท ํœฉ์˜ON sub45s lb90s dip0.40% tol0.30% +- mode Top10 meta: pool 87๊ฑด ยท ์ถ• 52๊ฐœ + +### ์ถ”์ฒœ (์ž๋™ ยท confirm ํ•„์ˆ˜) +1. **์‹ค๋งค DB ์ ์šฉ 1์ˆœ์œ„ โ†’ โ‘  ์‚ฌํ›„ํ•ฉ๊ฒฉ 1์œ„** (`optunaApply gated`) โ€” WR/PFยทmin_trades ์‚ฌํ›„ ํ†ต๊ณผ. +2. **๋ณ€๋™์„ฑยท์†์‹ค์ผ ์ค„์ด๊ธฐ โ†’ โ‘ก ์•ˆ์ • 1์œ„** (`stable`) โ€” PnL๋ณด๋‹ค ์ผ๋ณ„ ์•ˆ์ • ์šฐ์„  ์‹œ. +3. **2์ฐจ narrowยท๋Œ€ํ‘œ ์ˆซ์ž โ†’ โ‘ข mode_combo** โ€” ์ถ•๋ณ„ ์ตœ๋นˆ ์กฐ๋ฆฝ ยท trial ๋ฒˆํ˜ธ ์—†์Œ ยท ์ต์ ˆ์€ pool ์ตœ๋นˆ๊ฐ’ ์ฐธ๊ณ . +4. **โ‘ฃ mode Top10 1์œ„** โ€” ์–‘์ˆ˜ pool ์ „ํ˜• trial(๋‹ค์ถ• ๋ฐด๋“œ ๊ทผ์ ‘). **์ต์ ˆ ํ•˜๋‚˜๋กœ ์“ฐ์ง€ ๋ง ๊ฒƒ** ยท ํ‘œ์—์„œ ใ€Œ๋ณด๊ธฐใ€โ†’ consensus apply. + +## ์ด์ „ ์žฅ์—์„œ๋Š” +- ์‹ค๋งค ๋™๊ธฐ๊ฐ„ ์ฒญ์‚ฐ 6๊ฑด ยท ์Šน๋ฅ  67% ยท ํ•ฉ์‚ฐ PnL -9,520์› (๋ฐฑํ…Œ Optuna์™€ ์ˆซ์ž ๋‹ฌ๋ผ๋„ ์ •์ƒ โ€” ๊ณ ์ŠคํŠธยท์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑ ๊ฒฝ๋กœ ์ฐจ์ด). +- ์‚ฌํ›„ํ•ฉ๊ฒฉ 1์œ„: trial #123 ยท ๊ฑฐ๋ž˜ 3๊ฑด ยท ์Šน๋ฅ  100.0% ยท PF 9999.00 ยท PnL 13,982์› +- ์Šน๋ฅ ์ด ๋น„์ •์ƒ์ ์œผ๋กœ ๋†’๊ณ  ํ‘œ๋ณธ์ด ์ž‘์Šต๋‹ˆ๋‹ค โ†’ **ํ•ด๋‹น ์žฅ์—๋งŒ ๋งž๋Š” ๊ณผ์ ํ•ฉ** ์‹ ํ˜ธ. + +## ์•ž์œผ๋กœ ์žฅ์—์„œ๋Š” +- **1~2์ผ Optuna best๋ฅผ ๋ฐ”๋กœ ์‹ค๋งค์— ๋„ฃ์ง€ ๋งˆ์„ธ์š”.** ๋‹ค์ผ(โ‰ฅ5๊ฑฐ๋ž˜์ผ) ์žฌ๊ฒ€์ฆยท์›น๋ฐฑํ…Œ 1ํšŒ ํ›„ ๊ฒ€ํ† . +- ์ ์šฉ ์‹œ์—๋Š” `results_gated` ํ›„๋ณด๋งŒ. ํƒ์ƒ‰์šฉ best(objective)์™€ ๋‹ค๋ฅผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. +- ์žฅ์ด ์ข์•„์ง€๊ฑฐ๋‚˜ ๋ณ€๋™์„ฑ์ด ์ปค์ง€๋ฉด: ์†์ ˆยทํŠธ๋ ˆ์ผยท์‹œ๊ฐ„์ฐฝ์ด ๋จผ์ € ๊นจ์ง‘๋‹ˆ๋‹ค. ์Šน๋ฅ  ์ž๋ž‘๋ณด๋‹ค **์†์ ˆ์ด ์‚ด์•„ ์žˆ๋Š”์ง€**๋ฅผ ๋ณด์„ธ์š”. +- ์‚ฌํ›„ํ•ฉ๊ฒฉ์ด ์žˆ์–ด๋„ โ€˜๋‚ด์ผ๋„ ๊ฐ™์€ ์žฅโ€™์ด ์•„๋‹™๋‹ˆ๋‹ค. ํŽ˜์ดํผ/์†Œ์•กยท๋ชจ์˜๋กœ 1~2์ผ ๊ด€์ฐฐ ํ›„ ํ™•๋Œ€ํ•˜์„ธ์š”. + +_์ƒ์„ฑ: 2026-09-03 08:47:39 (rule)_ + +## AI ์ฝ”๋ฉ˜ํŠธ (์ด์ „ ์žฅ / ์•ž์œผ๋กœ ์žฅ) [gemini] + +## ์ด์ „ ์žฅ์—์„œ๋Š” + +์ง€๋‚œ Optuna ๋ฐฑํ…Œ์ŠคํŠธ ๊ฒฐ๊ณผ, ์‚ฌํ›„ํ•ฉ๊ฒฉ 1์œ„๋Š” 3๊ฑด ๊ฑฐ๋ž˜์—์„œ 100% ์Šน๋ฅ ๊ณผ 9999 PF๋ฅผ ๊ธฐ๋กํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š” ์‹ค๋งค์—์„œ ๊ด€์ฐฐ๋œ -9,520์› ์†์‹ค(6๊ฑด, 67% ์Šน๋ฅ )๊ณผ ํฐ ์ฐจ์ด๋ฅผ ๋ณด์ž…๋‹ˆ๋‹ค. 5๊ฑฐ๋ž˜์ผ์˜ ์งง์€ ๊ธฐ๊ฐ„๊ณผ 3๊ฑด์˜ ์ ์€ ๊ฑฐ๋ž˜๋Ÿ‰์œผ๋กœ ์–ป์€ ๋น„์ •์ƒ์ ์ธ ์Šน๋ฅ  ๋ฐ ์ˆ˜์ต๋ฅ ์€ **๊ณผ์ ํ•ฉ(Overfitting)์˜ ๋ช…ํ™•ํ•œ ๊ฒฝ๊ณ  ์‹ ํ˜ธ**์ž…๋‹ˆ๋‹ค. ํ•ด๋‹น ๊ธฐ๊ฐ„์—๋งŒ ์šฐ์—ฐํžˆ ์ž˜ ๋งž์•„๋–จ์–ด์ง„ ๊ฒฐ๊ณผ์ผ ๋ฟ, ์ผ๋ฐ˜์ ์ธ ์‹œ์žฅ์— ์ ์šฉํ•˜๊ธฐ ์–ด๋ ต์Šต๋‹ˆ๋‹ค. + +## ์•ž์œผ๋กœ ์žฅ์—์„œ๋Š” + +์ด๋ฒˆ Optuna ๊ฒฐ๊ณผ๋Š” ๊ณผ์ ํ•ฉ ์œ„ํ—˜ 43.0%, ์ ์šฉ ๊ฐ€๋Šฅ๋„ 57.0%๋กœ **ใ€Œ์ฃผ์˜ใ€** ํŒ์ •์ž…๋‹ˆ๋‹ค. ๋ฐฑํ…Œ์ŠคํŠธ ์ƒ์œ„ ์ „๋žต์ด๋ผ๋„ **์ ˆ๋Œ€ ์ฆ‰์‹œ ์‹ค๋งค์— ์ ์šฉํ•ด์„œ๋Š” ์•ˆ ๋ฉ๋‹ˆ๋‹ค.** **๊ณผ์ ํ•ฉยทํ‘œ๋ณธ ๋ถ€์กฑยท์‹ค๋งคโ†”๋ฐฑํ…Œ ๊ดด๋ฆฌ(๊ณ ์ŠคํŠธํผ์ง€ ๋“ฑ)**๋ฅผ ์ธ์ง€ํ•˜๊ณ , **๋‹ค์ผ(โ‰ฅ5๊ฑฐ๋ž˜์ผ) ์›น๋ฐฑํ…Œ์ŠคํŠธ์™€ ์†Œ์•ก ๋ชจ์˜ํˆฌ์ž**๋กœ ์ถ”๊ฐ€ ๊ฒ€์ฆ์ด ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค. DB 1์ˆœ์œ„๋Š” ์‚ฌํ›„ํ•ฉ๊ฒฉ์ผ ๋ฟ, **์ต์ ˆ ๋Œ€ํ‘œ ์ „๋žต์ด ์•„๋‹˜**์„ ๋ช…์‹ฌํ•˜๊ณ , ์†์ ˆ์ด ์‚ด์•„์žˆ๋Š”์ง€ ํ™•์ธํ•˜๋ฉฐ ์‹œ์žฅ ๋ณ€ํ™”์— ์œ ์—ฐํ•˜๊ฒŒ ๋Œ€์‘ํ•˜์„ธ์š”. ํŠน์ • ์ข…๋ชฉ ๋งค์ˆ˜ ์ถ”์ฒœ์ด๋‚˜ ํ™•์ • ์ˆ˜์ต์€ ์•ฝ์†ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. diff --git a/kis_trader/backtest/results/optuna_tail_tpe_20260903_093336.briefing.md b/kis_trader/backtest/results/optuna_tail_tpe_20260903_093336.briefing.md new file mode 100644 index 0000000..4459146 --- /dev/null +++ b/kis_trader/backtest/results/optuna_tail_tpe_20260903_093336.briefing.md @@ -0,0 +1,66 @@ +# Optuna ๋ธŒ๋ฆฌํ•‘ โ€” ๊ผฌ๋ฆฌ (tpe) +๊ธฐ๊ฐ„: 2026-08-24 ~ 2026-08-28 (๊ฑฐ๋ž˜์ผโ‰ˆ5์ผ) ยท trials 200/200 +ํƒ์ƒ‰ ๊ฒŒ์ดํŠธ: WRโ‰ฅ0% PFโ‰ฅ0 ยท min_tradesโ‰ฅ1 | ํ›„๋ณด ๊ฒŒ์ดํŠธ: WRโ‰ฅ40% PFโ‰ฅ1 ยท min_tradesโ‰ฅ1 +- min_trades=1: **ํ•ฉ๊ฒฉ ์ธ์ • ์ตœ์†Œ ๊ฑฐ๋ž˜ ๊ฑด์ˆ˜**(ํ‘œ๋ณธ ๋ถ€์กฑยท์šฐ์—ฐ ์Šน๋ฅ  ๋ฐฉ์ง€). ์ด๋ณด๋‹ค ์ ์€ ์กฐํ•ฉ์€ ํ•™์Šต/ํ›„๋ณด ์ง‘๊ณ„์—์„œ ์ œ์™ธ๋ฉ๋‹ˆ๋‹ค. +ํ•™์Šต์šฉ ํ†ต๊ณผ 106๊ฑด ยท ์‚ฌํ›„ํ•ฉ๊ฒฉ(results_gated) 102๊ฑด + +## ๊ณผ์ ํ•ฉยท์ ์šฉ ๊ฐ€๋Šฅ๋„ (ํœด๋ฆฌ์Šคํ‹ฑ) +- **๊ณผ์ ํ•ฉ ์œ„ํ—˜ 24.0%** ยท **์ ์šฉ ๊ฐ€๋Šฅ๋„ 76.0%** ยท ํŒ์ •: **์ƒ๋Œ€์ ์œผ๋กœ๋‚ฎ์Œ** โ€” ํœด๋ฆฌ์Šคํ‹ฑ์ƒ ์œ„ํ—˜ ์ƒ๋Œ€์  ๋‚ฎ์Œ โ€” ๊ทธ๋ž˜๋„ ๋‹ค์ผ ํ™•์ธ ๊ถŒ์žฅ + - ํ‘œ๋ณธ ์žฅ์ผ: +0.0p โ€” ๊ฑฐ๋ž˜์ผโ‰ˆ5์ผ โ€” ํ‘œ๋ณธ ์ผ์ˆ˜ ์ƒ๋Œ€์  ์–‘ํ˜ธ + - ๊ฑฐ๋ž˜ ํ‘œ๋ณธ: +18.0p โ€” ์ƒ์œ„ ํ›„๋ณด ๊ฑฐ๋ž˜ 3๊ฑด โ€” ํ‘œ๋ณธ ๋ถ€์กฑ + - ์Šน๋ฅ ยทPF ์ด์ƒ์น˜: +6.0p โ€” PF 12.11 + - ๊ฒŒ์ดํŠธ ์ปค๋ฒ„: +0.0p โ€” ์‚ฌํ›„ํ•ฉ๊ฒฉ 102๊ฑด ยท stable 9๊ฑด + - PnL ๊ณ ์›: +0.0p โ€” ๊ณ ์› ๋น„์œจ 1% (1๊ฑด) +- ์ž„๊ณ„๊ฐ’ ๋ถ„ํฌ ํ‘œ๋ณธ: results_gated ์ƒ์œ„ 30๊ฑด +| ํŒŒ๋ผ๋ฏธํ„ฐ | median | p25~p75 | mode(๋น„์œจ) | +|---|---:|---|---| +| `entry_mode` | โ€” | โ€” | align (100%) | +| `cand_limit` | 20.0 | 20.0 ~ 20.0 | 20 (90%) | +| `max_daily_change` | 35.0 | 30.0 ~ 45.5 | 20.0 (10%) | +| `min_drop_rate` | 0.0975 | 0.0575 ~ 0.115 | 0.11 (10%) | +| `min_recovery_ratio` | 0.13 | 0.1025 ~ 0.16 | 0.12 (13%) | +| `tail_ratio_min` | 0.9 | 0.7 ~ 1.075 | 0.8 (17%) | +| `tail_pct_min` | 0.0065 | 0.005 ~ 0.007875 | 0.005 (13%) | +| `max_rec_3m` | 0.88 | 0.85 ~ 0.91 | 0.9 (13%) | +| `shoulder_min_high` | 0.004 | 0.003 ~ 0.005 | 0.004 (30%) | +| `shoulder_cut_pct` | 0.0015 | 0.001 ~ 0.002375 | 0.001 (33%) | +| `stop_atr_mult` | 2.3 | 2.0 ~ 2.5 | 2.5 (13%) | +| `target_atr_mult` | 2.1 | 1.6 ~ 2.375 | 2.3 (17%) | +- _์ฐธ๊ณ : ๊ณผ์ ํ•ฉ%๋Š” ๊ต์ฐจ๊ฒ€์ฆ ์ ์ˆ˜๊ฐ€ ์•„๋‹ˆ๋ผ ํ‘œ๋ณธยท์ด์ƒ์น˜ยท๊ณ ์› ํœด๋ฆฌ์Šคํ‹ฑ์ž…๋‹ˆ๋‹ค. ์ ์šฉ ๊ฐ€๋Šฅ๋„%=100โˆ’๊ณผ์ ํ•ฉ์œ„ํ—˜%. DB ์ ์šฉ ๋ฒ„ํŠผ ํ™œ์„ฑ ์กฐ๊ฑด(gated PnL>0)๊ณผ๋Š” ๋ณ„๊ฐœ์ž…๋‹ˆ๋‹ค._ + +## ์ตœ์ข… ์„ ํƒ ํ›„๋ณด (๊ทœ์น™ ยท DB ์ ์šฉ ์ „ ํ™•์ธ) +- ์•„๋ž˜๋Š” **์—ญํ• ์ด ๋‹ค๋ฅธ** 4์ข… ํ›„๋ณด์ž…๋‹ˆ๋‹ค. mode Top10 1์œ„ โ‰  ์ต์ ˆ ๋Œ€ํ‘œ ยท **DB 1์ˆœ์œ„๋Š” ์‚ฌํ›„ํ•ฉ๊ฒฉ(gated)** ์ž…๋‹ˆ๋‹ค. +- mode pool: `positive` ยท scoring: `band_proximity_p25_p75` + +### ํ›„๋ณด 4์ข… +- **โ‘  ์‚ฌํ›„ํ•ฉ๊ฒฉ 1์œ„ (apply: gated)** (trial #167): PnL 11,576์› ยท WR 66.7% ยท PF 12.11 ยท ๊ฑฐ๋ž˜ 3๊ฑด ยท ์•ˆ์ •์ ์ˆ˜ 3946 ยท ํ˜ธ๊ฐ€OFF ยท ํœฉ์˜OFF +- **โ‘ก ์•ˆ์ • 1์œ„ (apply: stable)** (trial #167): PnL 11,576์› ยท WR 66.7% ยท PF 12.11 ยท ๊ฑฐ๋ž˜ 3๊ฑด ยท ์•ˆ์ •์ ์ˆ˜ 3946 ยท ํ˜ธ๊ฐ€OFF ยท ํœฉ์˜OFF +- **โ‘ข mode_combo (apply: mode)** (trial ์—†์Œ(์กฐ๋ฆฝ)): PnL 5,372์› ยท WR 100.0% ยท PF 9999.00 ยท ๊ฑฐ๋ž˜ 2๊ฑด ยท ์•ˆ์ •์ ์ˆ˜ 5372 ยท ํ˜ธ๊ฐ€OFF ยท ํœฉ์˜OFF +- **โ‘ฃ mode Top10 1์œ„ (apply: consensus ยท ๋ฐด๋“œ ์ „ํ˜• trial)** (trial #40): PnL 4,988์› ยท WR 100.0% ยท PF 9999.00 ยท ๊ฑฐ๋ž˜ 1๊ฑด ยท ์•ˆ์ •์ ์ˆ˜ 4988 ยท ๊ทผ์ ‘ 98.8% (47/52์ถ• ๋ฐด๋“œ์•ˆ) ยท ํ˜ธ๊ฐ€OFF ยท ํœฉ์˜OFF +- mode Top10 meta: pool 103๊ฑด ยท ์ถ• 52๊ฐœ + +### ์ถ”์ฒœ (์ž๋™ ยท confirm ํ•„์ˆ˜) +1. **์‹ค๋งค DB ์ ์šฉ 1์ˆœ์œ„ โ†’ โ‘  ์‚ฌํ›„ํ•ฉ๊ฒฉ 1์œ„** (`optunaApply gated`) โ€” WR/PFยทmin_trades ์‚ฌํ›„ ํ†ต๊ณผ. +2. **๋ณ€๋™์„ฑยท์†์‹ค์ผ ์ค„์ด๊ธฐ โ†’ โ‘ก ์•ˆ์ • 1์œ„** (`stable`) โ€” PnL๋ณด๋‹ค ์ผ๋ณ„ ์•ˆ์ • ์šฐ์„  ์‹œ. +3. **2์ฐจ narrowยท๋Œ€ํ‘œ ์ˆซ์ž โ†’ โ‘ข mode_combo** โ€” ์ถ•๋ณ„ ์ตœ๋นˆ ์กฐ๋ฆฝ ยท trial ๋ฒˆํ˜ธ ์—†์Œ ยท ์ต์ ˆ์€ pool ์ตœ๋นˆ๊ฐ’ ์ฐธ๊ณ . +4. **โ‘ฃ mode Top10 1์œ„** โ€” ์–‘์ˆ˜ pool ์ „ํ˜• trial(๋‹ค์ถ• ๋ฐด๋“œ ๊ทผ์ ‘). **์ต์ ˆ ํ•˜๋‚˜๋กœ ์“ฐ์ง€ ๋ง ๊ฒƒ** ยท ํ‘œ์—์„œ ใ€Œ๋ณด๊ธฐใ€โ†’ consensus apply. + +## ์ด์ „ ์žฅ์—์„œ๋Š” +- ์‹ค๋งค ๋™๊ธฐ๊ฐ„ ์ฒญ์‚ฐ 6๊ฑด ยท ์Šน๋ฅ  67% ยท ํ•ฉ์‚ฐ PnL -9,520์› (๋ฐฑํ…Œ Optuna์™€ ์ˆซ์ž ๋‹ฌ๋ผ๋„ ์ •์ƒ โ€” ๊ณ ์ŠคํŠธยท์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑ ๊ฒฝ๋กœ ์ฐจ์ด). +- ์‚ฌํ›„ํ•ฉ๊ฒฉ 1์œ„: trial #167 ยท ๊ฑฐ๋ž˜ 3๊ฑด ยท ์Šน๋ฅ  66.7% ยท PF 12.11 ยท PnL 11,576์› + +## ์•ž์œผ๋กœ ์žฅ์—์„œ๋Š” +- **1~2์ผ Optuna best๋ฅผ ๋ฐ”๋กœ ์‹ค๋งค์— ๋„ฃ์ง€ ๋งˆ์„ธ์š”.** ๋‹ค์ผ(โ‰ฅ5๊ฑฐ๋ž˜์ผ) ์žฌ๊ฒ€์ฆยท์›น๋ฐฑํ…Œ 1ํšŒ ํ›„ ๊ฒ€ํ† . +- ์ ์šฉ ์‹œ์—๋Š” `results_gated` ํ›„๋ณด๋งŒ. ํƒ์ƒ‰์šฉ best(objective)์™€ ๋‹ค๋ฅผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. +- ์žฅ์ด ์ข์•„์ง€๊ฑฐ๋‚˜ ๋ณ€๋™์„ฑ์ด ์ปค์ง€๋ฉด: ์†์ ˆยทํŠธ๋ ˆ์ผยท์‹œ๊ฐ„์ฐฝ์ด ๋จผ์ € ๊นจ์ง‘๋‹ˆ๋‹ค. ์Šน๋ฅ  ์ž๋ž‘๋ณด๋‹ค **์†์ ˆ์ด ์‚ด์•„ ์žˆ๋Š”์ง€**๋ฅผ ๋ณด์„ธ์š”. +- ์‚ฌํ›„ํ•ฉ๊ฒฉ์ด ์žˆ์–ด๋„ โ€˜๋‚ด์ผ๋„ ๊ฐ™์€ ์žฅโ€™์ด ์•„๋‹™๋‹ˆ๋‹ค. ํŽ˜์ดํผ/์†Œ์•กยท๋ชจ์˜๋กœ 1~2์ผ ๊ด€์ฐฐ ํ›„ ํ™•๋Œ€ํ•˜์„ธ์š”. + +_์ƒ์„ฑ: 2026-09-03 09:33:40 (rule)_ + +## AI ์ฝ”๋ฉ˜ํŠธ (์ด์ „ ์žฅ / ์•ž์œผ๋กœ ์žฅ) [gemini] + +## ์ด์ „ ์žฅ์—์„œ๋Š” +์‹ค๋งค ๋™๊ธฐ๊ฐ„ PnL์€ -9,520์›์ด์—ˆ์œผ๋‚˜, ๋ฐฑํ…Œ์ŠคํŠธ ์‚ฌํ›„ํ•ฉ๊ฒฉ 1์œ„(trial #167)๋Š” 3๊ฑด ๊ฑฐ๋ž˜๋กœ PnL 11,576์›์„ ๊ธฐ๋กํ–ˆ์Šต๋‹ˆ๋‹ค. ์‹ค๋งค์™€ ๋ฐฑํ…Œ ๊ฐ„์—๋Š” ๊ณ ์ŠคํŠธํผ์ง€ ๋“ฑ์œผ๋กœ ์ธํ•œ ๊ดด๋ฆฌ๊ฐ€ ์ปธ์Œ์„ ๋ช…ํ™•ํžˆ ์ธ์ง€ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. + +## ์•ž์œผ๋กœ ์žฅ์—์„œ๋Š” +5๊ฑฐ๋ž˜์ผ์˜ ๋งค์šฐ ์งง์€ ๊ธฐ๊ฐ„๊ณผ ๋‹จ 3๊ฑด์˜ ๊ฑฐ๋ž˜๋Š” ๊ณผ์ ํ•ฉ ๋ฐ ํ‘œ๋ณธ ๋ถ€์กฑ ์œ„ํ—˜์ด ํฝ๋‹ˆ๋‹ค. ํŠนํžˆ `mode Top10 1์œ„`๋Š” 1๊ฑด ๊ฑฐ๋ž˜์ด๋ฏ€๋กœ ์ต์ ˆ ๋Œ€ํ‘œ๋กœ ๋‹จ์ •ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ์‹ค๋งค ์ ์šฉ ์‹œ์—๋Š” `์‚ฌํ›„ํ•ฉ๊ฒฉ(gated)` ํ›„๋ณด๋ฅผ ์ตœ์†Œ 5์ผ ์ด์ƒ ์žฌ๊ฒ€์ฆ ํ›„, ํŽ˜์ดํผ/์†Œ์•ก์œผ๋กœ ์‹ ์ค‘ํ•˜๊ฒŒ ๊ด€์ฐฐํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๋ฐฑํ…Œ์ŠคํŠธ ์ˆ˜์ต๋ฅ ๋ณด๋‹ค ์‹ค๋งคโ†”๋ฐฑํ…Œ ๊ดด๋ฆฌ์— ์œ ์˜ํ•˜๋ฉฐ ์†์ ˆ ๊ธฐ๋Šฅ์ด ์‚ด์•„์žˆ๋Š”์ง€ ํ™•์ธ์ด ์ค‘์š”ํ•˜๋ฉฐ, ํ™•์ • ์ˆ˜์ต์€ ์•ฝ์†๋“œ๋ฆด ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. diff --git a/kis_trader/backtest/results/optuna_tail_tpe_20260903_094015.briefing.md b/kis_trader/backtest/results/optuna_tail_tpe_20260903_094015.briefing.md new file mode 100644 index 0000000..fca1e05 --- /dev/null +++ b/kis_trader/backtest/results/optuna_tail_tpe_20260903_094015.briefing.md @@ -0,0 +1,66 @@ +# Optuna ๋ธŒ๋ฆฌํ•‘ โ€” ๊ผฌ๋ฆฌ (tpe) +๊ธฐ๊ฐ„: 2026-08-24 ~ 2026-08-28 (๊ฑฐ๋ž˜์ผโ‰ˆ5์ผ) ยท trials 200/200 +ํƒ์ƒ‰ ๊ฒŒ์ดํŠธ: WRโ‰ฅ0% PFโ‰ฅ0 ยท min_tradesโ‰ฅ1 | ํ›„๋ณด ๊ฒŒ์ดํŠธ: WRโ‰ฅ40% PFโ‰ฅ1 ยท min_tradesโ‰ฅ1 +- min_trades=1: **ํ•ฉ๊ฒฉ ์ธ์ • ์ตœ์†Œ ๊ฑฐ๋ž˜ ๊ฑด์ˆ˜**(ํ‘œ๋ณธ ๋ถ€์กฑยท์šฐ์—ฐ ์Šน๋ฅ  ๋ฐฉ์ง€). ์ด๋ณด๋‹ค ์ ์€ ์กฐํ•ฉ์€ ํ•™์Šต/ํ›„๋ณด ์ง‘๊ณ„์—์„œ ์ œ์™ธ๋ฉ๋‹ˆ๋‹ค. +ํ•™์Šต์šฉ ํ†ต๊ณผ 76๊ฑด ยท ์‚ฌํ›„ํ•ฉ๊ฒฉ(results_gated) 60๊ฑด + +## ๊ณผ์ ํ•ฉยท์ ์šฉ ๊ฐ€๋Šฅ๋„ (ํœด๋ฆฌ์Šคํ‹ฑ) +- **๊ณผ์ ํ•ฉ ์œ„ํ—˜ 16.0%** ยท **์ ์šฉ ๊ฐ€๋Šฅ๋„ 84.0%** ยท ํŒ์ •: **์ƒ๋Œ€์ ์œผ๋กœ๋‚ฎ์Œ** โ€” ํœด๋ฆฌ์Šคํ‹ฑ์ƒ ์œ„ํ—˜ ์ƒ๋Œ€์  ๋‚ฎ์Œ โ€” ๊ทธ๋ž˜๋„ ๋‹ค์ผ ํ™•์ธ ๊ถŒ์žฅ + - ํ‘œ๋ณธ ์žฅ์ผ: +0.0p โ€” ๊ฑฐ๋ž˜์ผโ‰ˆ5์ผ โ€” ํ‘œ๋ณธ ์ผ์ˆ˜ ์ƒ๋Œ€์  ์–‘ํ˜ธ + - ๊ฑฐ๋ž˜ ํ‘œ๋ณธ: +10.0p โ€” ์ƒ์œ„ ํ›„๋ณด ๊ฑฐ๋ž˜ 4๊ฑด โ€” ํ•ด์„ ์‹œ ์ฃผ์˜ + - ์Šน๋ฅ ยทPF ์ด์ƒ์น˜: +6.0p โ€” PF 11.42 + - ๊ฒŒ์ดํŠธ ์ปค๋ฒ„: +0.0p โ€” ์‚ฌํ›„ํ•ฉ๊ฒฉ 60๊ฑด ยท stable 10๊ฑด + - PnL ๊ณ ์›: +0.0p โ€” ๊ณ ์› ๋น„์œจ 2% (1๊ฑด) +- ์ž„๊ณ„๊ฐ’ ๋ถ„ํฌ ํ‘œ๋ณธ: results_gated ์ƒ์œ„ 30๊ฑด +| ํŒŒ๋ผ๋ฏธํ„ฐ | median | p25~p75 | mode(๋น„์œจ) | +|---|---:|---|---| +| `entry_mode` | โ€” | โ€” | align (100%) | +| `cand_limit` | 20.0 | 5.0 ~ 20.0 | 20 (73%) | +| `max_daily_change` | 22.5 | 20.0 ~ 28.0 | 22.0 (17%) | +| `min_drop_rate` | 0.035 | 0.02125 ~ 0.045 | 0.03 (17%) | +| `min_recovery_ratio` | 0.1 | 0.09 ~ 0.145 | 0.09 (23%) | +| `tail_ratio_min` | 0.9 | 0.7 ~ 1.1 | 1.1 (23%) | +| `tail_pct_min` | 0.001 | 0.000625 ~ 0.004 | 0.0005 (27%) | +| `max_rec_3m` | 0.945 | 0.91 ~ 0.96 | 0.96 (17%) | +| `shoulder_min_high` | 0.0095 | 0.00725 ~ 0.011 | 0.01 (20%) | +| `shoulder_cut_pct` | 0.00175 | 0.0015 ~ 0.003875 | 0.0015 (27%) | +| `stop_atr_mult` | 1.3 | 1.0 ~ 1.6 | 0.8 (17%) | +| `target_atr_mult` | 1.3 | 1.125 ~ 2.05 | 1.2 (17%) | +- _์ฐธ๊ณ : ๊ณผ์ ํ•ฉ%๋Š” ๊ต์ฐจ๊ฒ€์ฆ ์ ์ˆ˜๊ฐ€ ์•„๋‹ˆ๋ผ ํ‘œ๋ณธยท์ด์ƒ์น˜ยท๊ณ ์› ํœด๋ฆฌ์Šคํ‹ฑ์ž…๋‹ˆ๋‹ค. ์ ์šฉ ๊ฐ€๋Šฅ๋„%=100โˆ’๊ณผ์ ํ•ฉ์œ„ํ—˜%. DB ์ ์šฉ ๋ฒ„ํŠผ ํ™œ์„ฑ ์กฐ๊ฑด(gated PnL>0)๊ณผ๋Š” ๋ณ„๊ฐœ์ž…๋‹ˆ๋‹ค._ + +## ์ตœ์ข… ์„ ํƒ ํ›„๋ณด (๊ทœ์น™ ยท DB ์ ์šฉ ์ „ ํ™•์ธ) +- ์•„๋ž˜๋Š” **์—ญํ• ์ด ๋‹ค๋ฅธ** 4์ข… ํ›„๋ณด์ž…๋‹ˆ๋‹ค. mode Top10 1์œ„ โ‰  ์ต์ ˆ ๋Œ€ํ‘œ ยท **DB 1์ˆœ์œ„๋Š” ์‚ฌํ›„ํ•ฉ๊ฒฉ(gated)** ์ž…๋‹ˆ๋‹ค. +- mode pool: `positive` ยท scoring: `band_proximity_p25_p75` + +### ํ›„๋ณด 4์ข… +- **โ‘  ์‚ฌํ›„ํ•ฉ๊ฒฉ 1์œ„ (apply: gated)** (trial #92): PnL 13,641์› ยท WR 75.0% ยท PF 11.42 ยท ๊ฑฐ๋ž˜ 4๊ฑด ยท ์•ˆ์ •์ ์ˆ˜ 6321 ยท ํ˜ธ๊ฐ€OFF ยท ํœฉ์˜OFF +- **โ‘ก ์•ˆ์ • 1์œ„ (apply: stable)** (trial #92): PnL 13,641์› ยท WR 75.0% ยท PF 11.42 ยท ๊ฑฐ๋ž˜ 4๊ฑด ยท ์•ˆ์ •์ ์ˆ˜ 6321 ยท ํ˜ธ๊ฐ€OFF ยท ํœฉ์˜OFF +- **โ‘ข mode_combo (apply: mode)** (trial ์—†์Œ(์กฐ๋ฆฝ)): PnL 8,758์› ยท WR 50.0% ยท PF 3.27 ยท ๊ฑฐ๋ž˜ 4๊ฑด ยท ์•ˆ์ •์ ์ˆ˜ 3036 ยท ํ˜ธ๊ฐ€OFF ยท ํœฉ์˜OFF +- **โ‘ฃ mode Top10 1์œ„ (apply: consensus ยท ๋ฐด๋“œ ์ „ํ˜• trial)** (trial #92): PnL 13,641์› ยท WR 75.0% ยท PF 11.42 ยท ๊ฑฐ๋ž˜ 4๊ฑด ยท ์•ˆ์ •์ ์ˆ˜ 6321 ยท ๊ทผ์ ‘ 95.0% (42/52์ถ• ๋ฐด๋“œ์•ˆ) ยท ํ˜ธ๊ฐ€OFF ยท ํœฉ์˜OFF +- mode Top10 meta: pool 70๊ฑด ยท ์ถ• 52๊ฐœ + +### ์ถ”์ฒœ (์ž๋™ ยท confirm ํ•„์ˆ˜) +1. **์‹ค๋งค DB ์ ์šฉ 1์ˆœ์œ„ โ†’ โ‘  ์‚ฌํ›„ํ•ฉ๊ฒฉ 1์œ„** (`optunaApply gated`) โ€” WR/PFยทmin_trades ์‚ฌํ›„ ํ†ต๊ณผ. +2. **๋ณ€๋™์„ฑยท์†์‹ค์ผ ์ค„์ด๊ธฐ โ†’ โ‘ก ์•ˆ์ • 1์œ„** (`stable`) โ€” PnL๋ณด๋‹ค ์ผ๋ณ„ ์•ˆ์ • ์šฐ์„  ์‹œ. +3. **2์ฐจ narrowยท๋Œ€ํ‘œ ์ˆซ์ž โ†’ โ‘ข mode_combo** โ€” ์ถ•๋ณ„ ์ตœ๋นˆ ์กฐ๋ฆฝ ยท trial ๋ฒˆํ˜ธ ์—†์Œ ยท ์ต์ ˆ์€ pool ์ตœ๋นˆ๊ฐ’ ์ฐธ๊ณ . +4. **โ‘ฃ mode Top10 1์œ„** โ€” ์–‘์ˆ˜ pool ์ „ํ˜• trial(๋‹ค์ถ• ๋ฐด๋“œ ๊ทผ์ ‘). **์ต์ ˆ ํ•˜๋‚˜๋กœ ์“ฐ์ง€ ๋ง ๊ฒƒ** ยท ํ‘œ์—์„œ ใ€Œ๋ณด๊ธฐใ€โ†’ consensus apply. + +## ์ด์ „ ์žฅ์—์„œ๋Š” +- ์‹ค๋งค ๋™๊ธฐ๊ฐ„ ์ฒญ์‚ฐ 6๊ฑด ยท ์Šน๋ฅ  67% ยท ํ•ฉ์‚ฐ PnL -9,520์› (๋ฐฑํ…Œ Optuna์™€ ์ˆซ์ž ๋‹ฌ๋ผ๋„ ์ •์ƒ โ€” ๊ณ ์ŠคํŠธยท์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑ ๊ฒฝ๋กœ ์ฐจ์ด). +- ์‚ฌํ›„ํ•ฉ๊ฒฉ 1์œ„: trial #92 ยท ๊ฑฐ๋ž˜ 4๊ฑด ยท ์Šน๋ฅ  75.0% ยท PF 11.42 ยท PnL 13,641์› + +## ์•ž์œผ๋กœ ์žฅ์—์„œ๋Š” +- **1~2์ผ Optuna best๋ฅผ ๋ฐ”๋กœ ์‹ค๋งค์— ๋„ฃ์ง€ ๋งˆ์„ธ์š”.** ๋‹ค์ผ(โ‰ฅ5๊ฑฐ๋ž˜์ผ) ์žฌ๊ฒ€์ฆยท์›น๋ฐฑํ…Œ 1ํšŒ ํ›„ ๊ฒ€ํ† . +- ์ ์šฉ ์‹œ์—๋Š” `results_gated` ํ›„๋ณด๋งŒ. ํƒ์ƒ‰์šฉ best(objective)์™€ ๋‹ค๋ฅผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. +- ์žฅ์ด ์ข์•„์ง€๊ฑฐ๋‚˜ ๋ณ€๋™์„ฑ์ด ์ปค์ง€๋ฉด: ์†์ ˆยทํŠธ๋ ˆ์ผยท์‹œ๊ฐ„์ฐฝ์ด ๋จผ์ € ๊นจ์ง‘๋‹ˆ๋‹ค. ์Šน๋ฅ  ์ž๋ž‘๋ณด๋‹ค **์†์ ˆ์ด ์‚ด์•„ ์žˆ๋Š”์ง€**๋ฅผ ๋ณด์„ธ์š”. +- ์‚ฌํ›„ํ•ฉ๊ฒฉ์ด ์žˆ์–ด๋„ โ€˜๋‚ด์ผ๋„ ๊ฐ™์€ ์žฅโ€™์ด ์•„๋‹™๋‹ˆ๋‹ค. ํŽ˜์ดํผ/์†Œ์•กยท๋ชจ์˜๋กœ 1~2์ผ ๊ด€์ฐฐ ํ›„ ํ™•๋Œ€ํ•˜์„ธ์š”. + +_์ƒ์„ฑ: 2026-09-03 09:40:18 (rule)_ + +## AI ์ฝ”๋ฉ˜ํŠธ (์ด์ „ ์žฅ / ์•ž์œผ๋กœ ์žฅ) [gemini] + +### ์ด์ „ ์žฅ์—์„œ๋Š” +์ง€๋‚œ 5์ผ๊ฐ„์˜ ์‹ค์ œ ๋งค๋งค์—์„œ๋Š” 6๊ฑด์˜ ์ฒญ์‚ฐ์œผ๋กœ -9,520์›์˜ ์†์‹ค์ด ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. ๋ฐฑํ…Œ์ŠคํŠธ Optuna ๊ฒฐ๊ณผ๋Š” 5๊ฑฐ๋ž˜์ผ์ด๋ผ๋Š” ์งง์€ ๊ธฐ๊ฐ„ ๋™์•ˆ ๋‹จ 4๊ฑด์˜ ๊ฑฐ๋ž˜๋กœ PnL 13,641์›, ์Šน๋ฅ  75%, PF 11.42๋ฅผ ๊ธฐ๋กํ•œ trial #92๊ฐ€ ์‚ฌํ›„ํ•ฉ๊ฒฉ 1์œ„๋ฅผ ์ฐจ์ง€ํ–ˆ์Šต๋‹ˆ๋‹ค. ์‹ค์ œ ๋งค๋งค์™€ ๋ฐฑํ…Œ์ŠคํŠธ ๊ฒฐ๊ณผ ๊ฐ„์˜ ํฐ ๊ดด๋ฆฌ๋Š” ๊ณ ์ŠคํŠธํผ์ง€, ์œ ๋‹ˆ๋ฒ„์Šค ์ฐจ์ด ๋“ฑ์œผ๋กœ ์ธํ•ด ๋Š˜ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋Š” ํ˜„์ƒ์ž…๋‹ˆ๋‹ค. + +### ์•ž์œผ๋กœ ์žฅ์—์„œ๋Š” +์ด๋ฒˆ 5์ผ ๋ฐฑํ…Œ์ŠคํŠธ๋Š” ๊ฑฐ๋ž˜ 4๊ฑด์ด๋ผ๋Š” ๊ทนํžˆ ์ ์€ ํ‘œ๋ณธ์œผ๋กœ ๋†’์€ PF๋ฅผ ๊ธฐ๋กํ•˜์—ฌ ๊ณผ์ ํ•ฉ ๋ฐ ์šฐ์—ฐํ•œ ์Šน๋ฅ ์ผ ๊ฐ€๋Šฅ์„ฑ์ด ๋งค์šฐ ๋†’์Šต๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ Optuna ์ตœ๊ณ  ๊ฒฐ๊ณผ๋ฅผ ๋ฐ”๋กœ ์‹ค๋งค์— ์ ์šฉํ•˜๋Š” ๊ฒƒ์€ ์œ„ํ—˜ํ•ฉ๋‹ˆ๋‹ค. ์‹ค๋งค์™€ ๋ฐฑํ…Œ์ŠคํŠธ ๊ฐ„ ๊ดด๋ฆฌ ํ˜„์ƒ์ด ์ด๋ฏธ ๋‚˜ํƒ€๋‚˜๋ฏ€๋กœ, ๋ฐ˜๋“œ์‹œ ํŽ˜์ดํผ ๋˜๋Š” ์†Œ์•ก์œผ๋กœ 1~2์ผ ์ถ”๊ฐ€ ๊ด€์ฐฐ ํ›„ ์‹ ์ค‘ํžˆ ํ™•๋Œ€ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๋˜ํ•œ, DB 1์ˆœ์œ„๋Š” ์‚ฌํ›„ํ•ฉ๊ฒฉ(gated)์ด๋ฉฐ, `mode Top10 1์œ„`๋ฅผ ์ต์ ˆ ๋Œ€ํ‘œ๋กœ ๋‹จ์ •ํ•˜์ง€ ๋งˆ์‹ญ์‹œ์˜ค. ํ™•์ • ์ˆ˜์ต์„ ์•ฝ์†ํ•  ์ˆ˜ ์—†์œผ๋ฉฐ, ์‹œ์žฅ ๋ณ€ํ™” ์‹œ ์†์ ˆ์„  ์œ ์ง€ ์—ฌ๋ถ€๋ฅผ ์ตœ์šฐ์„ ์œผ๋กœ ํ™•์ธํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. diff --git a/kis_trader/backtest/results/optuna_tail_tpe_20260904_203523.briefing.md b/kis_trader/backtest/results/optuna_tail_tpe_20260904_203523.briefing.md new file mode 100644 index 0000000..a7e50a3 --- /dev/null +++ b/kis_trader/backtest/results/optuna_tail_tpe_20260904_203523.briefing.md @@ -0,0 +1,69 @@ +# Optuna ๋ธŒ๋ฆฌํ•‘ โ€” ๊ผฌ๋ฆฌ (tpe) +๊ธฐ๊ฐ„: 2026-09-04 ~ 2026-09-04 (๊ฑฐ๋ž˜์ผโ‰ˆ1์ผ) ยท trials 200/200 +ํƒ์ƒ‰ ๊ฒŒ์ดํŠธ: WRโ‰ฅ0% PFโ‰ฅ0 ยท min_tradesโ‰ฅ1 | ํ›„๋ณด ๊ฒŒ์ดํŠธ: WRโ‰ฅ40% PFโ‰ฅ1 ยท min_tradesโ‰ฅ1 +- min_trades=1: **ํ•ฉ๊ฒฉ ์ธ์ • ์ตœ์†Œ ๊ฑฐ๋ž˜ ๊ฑด์ˆ˜**(ํ‘œ๋ณธ ๋ถ€์กฑยท์šฐ์—ฐ ์Šน๋ฅ  ๋ฐฉ์ง€). ์ด๋ณด๋‹ค ์ ์€ ์กฐํ•ฉ์€ ํ•™์Šต/ํ›„๋ณด ์ง‘๊ณ„์—์„œ ์ œ์™ธ๋ฉ๋‹ˆ๋‹ค. +ํ•™์Šต์šฉ ํ†ต๊ณผ 169๊ฑด ยท ์‚ฌํ›„ํ•ฉ๊ฒฉ(results_gated) 81๊ฑด + +## ๊ณผ์ ํ•ฉยท์ ์šฉ ๊ฐ€๋Šฅ๋„ (ํœด๋ฆฌ์Šคํ‹ฑ) +- **๊ณผ์ ํ•ฉ ์œ„ํ—˜ 40.0%** ยท **์ ์šฉ ๊ฐ€๋Šฅ๋„ 60.0%** ยท ํŒ์ •: **์ฃผ์˜** โ€” ์ ์šฉ ๊ฐ€๋Šฅ๋„ ์ค‘๊ฐ„ โ€” ๋‹ค์ผ(โ‰ฅ5์ผ) ์žฌ๊ฒ€์ฆยท์›น๋ฐฑํ…Œ ํ›„ ์†Œ์•ก๋งŒ + - ํ‘œ๋ณธ ์žฅ์ผ: +40.0p โ€” ๊ฑฐ๋ž˜์ผโ‰ˆ1์ผ โ€” ๋‹จ์ผ ์žฅ ๊ณผ์ ํ•ฉ ์œ„ํ—˜ ์ตœ๋Œ€ + - ๊ฑฐ๋ž˜ ํ‘œ๋ณธ: +0.0p โ€” ์ƒ์œ„ ํ›„๋ณด ๊ฑฐ๋ž˜ 88๊ฑด โ€” ์ƒ๋Œ€์  ์–‘ํ˜ธ + - ์Šน๋ฅ ยทPF ์ด์ƒ์น˜: +0.0p โ€” ์ด์ƒ์น˜ ์—†์Œ + - ๊ฒŒ์ดํŠธ ์ปค๋ฒ„: +0.0p โ€” ์‚ฌํ›„ํ•ฉ๊ฒฉ 81๊ฑด ยท stable 10๊ฑด + - PnL ๊ณ ์›: +0.0p โ€” ๊ณ ์› ๋น„์œจ 1% (1๊ฑด) +- ์ž„๊ณ„๊ฐ’ ๋ถ„ํฌ ํ‘œ๋ณธ: results_gated ์ƒ์œ„ 30๊ฑด +| ํŒŒ๋ผ๋ฏธํ„ฐ | median | p25~p75 | mode(๋น„์œจ) | +|---|---:|---|---| +| `entry_mode` | โ€” | โ€” | align (100%) | +| `cand_limit` | 0.0 | 0.0 ~ 15.0 | 0 (73%) | +| `max_daily_change` | 40.5 | 29.25 ~ 49.75 | 33.0 (7%) | +| `min_drop_rate` | 0.01 | 0.005 ~ 0.01 | 0.01 (40%) | +| `min_recovery_ratio` | 0.145 | 0.12 ~ 0.17 | 0.15 (13%) | +| `tail_ratio_min` | 1.25 | 1.125 ~ 1.4 | 1.2 (23%) | +| `tail_pct_min` | 0.006 | 0.00375 ~ 0.0075 | 0.0075 (17%) | +| `max_rec_3m` | 0.78 | 0.76 ~ 0.84 | 0.77 (13%) | +| `shoulder_min_high` | 0.003 | 0.002 ~ 0.004 | 0.002 (37%) | +| `shoulder_cut_pct` | 0.002 | 0.0015 ~ 0.0025 | 0.002 (33%) | +| `stop_atr_mult` | 2.0 | 1.45 ~ 2.375 | 2.0 (13%) | +| `target_atr_mult` | 1.8 | 1.5 ~ 2.1 | 1.8 (23%) | +- _์ฐธ๊ณ : ๊ณผ์ ํ•ฉ%๋Š” ๊ต์ฐจ๊ฒ€์ฆ ์ ์ˆ˜๊ฐ€ ์•„๋‹ˆ๋ผ ํ‘œ๋ณธยท์ด์ƒ์น˜ยท๊ณ ์› ํœด๋ฆฌ์Šคํ‹ฑ์ž…๋‹ˆ๋‹ค. ์ ์šฉ ๊ฐ€๋Šฅ๋„%=100โˆ’๊ณผ์ ํ•ฉ์œ„ํ—˜%. DB ์ ์šฉ ๋ฒ„ํŠผ ํ™œ์„ฑ ์กฐ๊ฑด(gated PnL>0)๊ณผ๋Š” ๋ณ„๊ฐœ์ž…๋‹ˆ๋‹ค._ + +## ์ตœ์ข… ์„ ํƒ ํ›„๋ณด (๊ทœ์น™ ยท DB ์ ์šฉ ์ „ ํ™•์ธ) +- ์•„๋ž˜๋Š” **์—ญํ• ์ด ๋‹ค๋ฅธ** 4์ข… ํ›„๋ณด์ž…๋‹ˆ๋‹ค. mode Top10 1์œ„ โ‰  ์ต์ ˆ ๋Œ€ํ‘œ ยท **DB 1์ˆœ์œ„๋Š” ์‚ฌํ›„ํ•ฉ๊ฒฉ(gated)** ์ž…๋‹ˆ๋‹ค. +- mode pool: `positive` ยท scoring: `band_proximity_p25_p75` + +### ํ›„๋ณด 4์ข… +- **โ‘  ์‚ฌํ›„ํ•ฉ๊ฒฉ 1์œ„ (apply: gated)** (trial #187): PnL 87,331์› ยท WR 59.1% ยท PF 1.90 ยท ๊ฑฐ๋ž˜ 88๊ฑด ยท ์•ˆ์ •์ ์ˆ˜ -4798 ยท ํ˜ธ๊ฐ€ON spr2.1 r0.30 askร—33 ยท ํœฉ์˜OFF +- **โ‘ก ์•ˆ์ • 1์œ„ (apply: stable)** (trial #51): PnL 22,258์› ยท WR 52.4% ยท PF 1.54 ยท ๊ฑฐ๋ž˜ 21๊ฑด ยท ์•ˆ์ •์ ์ˆ˜ 10209 ยท ํ˜ธ๊ฐ€ON spr3.3 r1.30 askร—24 ยท ํœฉ์˜ON sub60s lb120s dip1.00% tol0.15% +- **โ‘ข mode_combo (apply: mode)** (trial ์—†์Œ(์กฐ๋ฆฝ)): PnL -2,867์› ยท WR 57.2% ยท PF 0.86 ยท ๊ฑฐ๋ž˜ 250๊ฑด ยท ์•ˆ์ •์ ์ˆ˜ -1648 ยท ํ˜ธ๊ฐ€ON spr0.6 r0.30 askร—15 ยท ํœฉ์˜OFF +- **โ‘ฃ mode Top10 1์œ„ (apply: consensus ยท ๋ฐด๋“œ ์ „ํ˜• trial)** (trial #23): PnL 26,652์› ยท WR 54.5% ยท PF 1.63 ยท ๊ฑฐ๋ž˜ 33๊ฑด ยท ์•ˆ์ •์ ์ˆ˜ -1606 ยท ๊ทผ์ ‘ 97.5% (46/52์ถ• ๋ฐด๋“œ์•ˆ) ยท ํ˜ธ๊ฐ€ON spr3.3 r1.40 askร—15 ยท ํœฉ์˜ON sub15s lb90s dip0.50% tol0.05% +- mode Top10 meta: pool 81๊ฑด ยท ์ถ• 52๊ฐœ + +### ์ถ”์ฒœ (์ž๋™ ยท confirm ํ•„์ˆ˜) +1. **์‹ค๋งค DB ์ ์šฉ 1์ˆœ์œ„ โ†’ โ‘  ์‚ฌํ›„ํ•ฉ๊ฒฉ 1์œ„** (`optunaApply gated`) โ€” WR/PFยทmin_trades ์‚ฌํ›„ ํ†ต๊ณผ. +2. **๋ณ€๋™์„ฑยท์†์‹ค์ผ ์ค„์ด๊ธฐ โ†’ โ‘ก ์•ˆ์ • 1์œ„** (`stable`) โ€” PnL๋ณด๋‹ค ์ผ๋ณ„ ์•ˆ์ • ์šฐ์„  ์‹œ. +3. **2์ฐจ narrowยท๋Œ€ํ‘œ ์ˆซ์ž โ†’ โ‘ข mode_combo** โ€” ์ถ•๋ณ„ ์ตœ๋นˆ ์กฐ๋ฆฝ ยท trial ๋ฒˆํ˜ธ ์—†์Œ ยท ์ต์ ˆ์€ pool ์ตœ๋นˆ๊ฐ’ ์ฐธ๊ณ . +4. **โ‘ฃ mode Top10 1์œ„** โ€” ์–‘์ˆ˜ pool ์ „ํ˜• trial(๋‹ค์ถ• ๋ฐด๋“œ ๊ทผ์ ‘). **์ต์ ˆ ํ•˜๋‚˜๋กœ ์“ฐ์ง€ ๋ง ๊ฒƒ** ยท ํ‘œ์—์„œ ใ€Œ๋ณด๊ธฐใ€โ†’ consensus apply. + +## ์ด์ „ ์žฅ์—์„œ๋Š” +- ์‹ค๋งค ๋™๊ธฐ๊ฐ„ ์ฒญ์‚ฐ 8๊ฑด ยท ์Šน๋ฅ  50% ยท ํ•ฉ์‚ฐ PnL 121,682์› (๋ฐฑํ…Œ Optuna์™€ ์ˆซ์ž ๋‹ฌ๋ผ๋„ ์ •์ƒ โ€” ๊ณ ์ŠคํŠธยท์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑ ๊ฒฝ๋กœ ์ฐจ์ด). +- ์‚ฌํ›„ํ•ฉ๊ฒฉ 1์œ„: trial #187 ยท ๊ฑฐ๋ž˜ 88๊ฑด ยท ์Šน๋ฅ  59.1% ยท PF 1.90 ยท PnL 87,331์› +- ํ‘œ๋ณธ ์žฅ์ด 1์ผ๋ฟ์ด๋ผ, โ€˜์ด์ „ ์žฅ์— ์ž˜ ๋จนํžŒ ์ˆซ์žโ€™์ผ ๋ฟ **์ถ”์„ธ๊ฐ€ ๋ฐ”๋€Œ๋ฉด ๋ฐ”๋กœ ๊นจ์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.** + +## ์•ž์œผ๋กœ ์žฅ์—์„œ๋Š” +- **1~2์ผ Optuna best๋ฅผ ๋ฐ”๋กœ ์‹ค๋งค์— ๋„ฃ์ง€ ๋งˆ์„ธ์š”.** ๋‹ค์ผ(โ‰ฅ5๊ฑฐ๋ž˜์ผ) ์žฌ๊ฒ€์ฆยท์›น๋ฐฑํ…Œ 1ํšŒ ํ›„ ๊ฒ€ํ† . +- ์ ์šฉ ์‹œ์—๋Š” `results_gated` ํ›„๋ณด๋งŒ. ํƒ์ƒ‰์šฉ best(objective)์™€ ๋‹ค๋ฅผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. +- ์žฅ์ด ์ข์•„์ง€๊ฑฐ๋‚˜ ๋ณ€๋™์„ฑ์ด ์ปค์ง€๋ฉด: ์†์ ˆยทํŠธ๋ ˆ์ผยท์‹œ๊ฐ„์ฐฝ์ด ๋จผ์ € ๊นจ์ง‘๋‹ˆ๋‹ค. ์Šน๋ฅ  ์ž๋ž‘๋ณด๋‹ค **์†์ ˆ์ด ์‚ด์•„ ์žˆ๋Š”์ง€**๋ฅผ ๋ณด์„ธ์š”. +- ์‚ฌํ›„ํ•ฉ๊ฒฉ์ด ์žˆ์–ด๋„ โ€˜๋‚ด์ผ๋„ ๊ฐ™์€ ์žฅโ€™์ด ์•„๋‹™๋‹ˆ๋‹ค. ํŽ˜์ดํผ/์†Œ์•กยท๋ชจ์˜๋กœ 1~2์ผ ๊ด€์ฐฐ ํ›„ ํ™•๋Œ€ํ•˜์„ธ์š”. + +_์ƒ์„ฑ: 2026-09-04 20:35:25 (rule)_ + +## AI ์ฝ”๋ฉ˜ํŠธ (์ด์ „ ์žฅ / ์•ž์œผ๋กœ ์žฅ) [gemini] + +**์ด์ „ ์žฅ์—์„œ๋Š”** + +์ง€๋‚œ 2026๋…„ 9์›” 4์ผ ๋‹จ ํ•˜๋ฃจ์˜ Optuna TPE ๋ฐฑํ…Œ์ŠคํŠธ ๊ฒฐ๊ณผ, ์ด 81๊ฐœ์˜ ์œ ํšจ ์ „๋žต์ด ์‚ฌํ›„ ํ•ฉ๊ฒฉ ๊ธฐ์ค€์„ ํ†ต๊ณผํ–ˆ์Šต๋‹ˆ๋‹ค. ํŠนํžˆ ์‚ฌํ›„ํ•ฉ๊ฒฉ 1์œ„(#187)๋Š” ์Šน๋ฅ  59.1%, PF 1.90์œผ๋กœ ์šฐ์ˆ˜ํ•œ ์„ฑ๊ณผ๋ฅผ ๋ณด์˜€์œผ๋‚˜, ์‹ค์ œ ์šด์šฉ์—์„œ๋Š” 8๊ฑด ๊ฑฐ๋ž˜์— ์Šน๋ฅ  50%, 12๋งŒ ์›๋Œ€ ์ˆ˜์ต์œผ๋กœ ๋ฐฑํ…Œ์ŠคํŠธ์™€ ์ฐจ์ด๊ฐ€ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š” ๋ฐฑํ…Œ์ŠคํŠธ ํ™˜๊ฒฝ๊ณผ ์‹ค์ œ ์‹œ์žฅ์˜ ๊ดด๋ฆฌ(๊ณ ์ŠคํŠธ ํผ์ง€, ์Šฌ๋ฆฌํ”ผ์ง€ ๋“ฑ) ๋•Œ๋ฌธ์ด๋ฉฐ, ๋‹จ์ผ ์žฅ์ผ ๋ฐฑํ…Œ์ŠคํŠธ๋Š” ๊ณผ์ ํ•ฉ ์œ„ํ—˜์ด ๋งค์šฐ ๋†’์Šต๋‹ˆ๋‹ค. + +**์•ž์œผ๋กœ ์žฅ์—์„œ๋Š”** + +๋‹จ์ผ ๊ฑฐ๋ž˜์ผ ๋ฐฑํ…Œ์ŠคํŠธ๋Š” ๊ณผ์ ํ•ฉ ์œ„ํ—˜์ด ๋†’์•„ ๊ณง๋ฐ”๋กœ ์‹ค๋งค์— ์ ์šฉํ•˜๋Š” ๊ฒƒ์€ ์œ„ํ—˜ํ•ฉ๋‹ˆ๋‹ค. ์ตœ์†Œ 5์ผ ์ด์ƒ ๋‹ค์ผ ๊ฒ€์ฆ๊ณผ ์›น ๋ฐฑํ…Œ์ŠคํŠธ๋ฅผ ๊ฑฐ์ณ ์ ์šฉ ๊ฐ€๋Šฅ๋„๋ฅผ ๋†’์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค. Optuna์˜ DB 1์ˆœ์œ„(์‚ฌํ›„ํ•ฉ๊ฒฉ) ์ „๋žต์„ ์šฐ์„  ๊ฒ€ํ† ํ•˜๋˜, Top10 1์œ„๊ฐ€ ์ ˆ๋Œ€์ ์ธ ์ต์ ˆ ์ „๋žต์ž„์„ ๋‹จ์ •ํ•˜์ง€ ๋งˆ์‹ญ์‹œ์˜ค. ์žฅ์„ธ ๋ณ€ํ™”์— ๋”ฐ๋ผ ์†์ ˆ์„  ์œ ์ง€๊ฐ€ ๋” ์ค‘์š”ํ•˜๋ฉฐ, ๋ฐฑํ…Œ์ŠคํŠธ ๊ฒฐ๊ณผ๋Š” ํ™•์ • ์ˆ˜์ต์„ ๋ณด์žฅํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋ฐ˜๋“œ์‹œ ๋ชจ์˜/์†Œ์•ก์œผ๋กœ ๊ด€์ฐฐ ํ›„ ์ ์ง„์ ์œผ๋กœ ๊ทœ๋ชจ๋ฅผ ํ™•๋Œ€ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ํŠน์ • ์ข…๋ชฉ ๋งค์ˆ˜๋Š” ์ถ”์ฒœํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. diff --git a/kis_trader/backtest/results/optuna_tail_tpe_20260904_204003.briefing.md b/kis_trader/backtest/results/optuna_tail_tpe_20260904_204003.briefing.md new file mode 100644 index 0000000..bc87133 --- /dev/null +++ b/kis_trader/backtest/results/optuna_tail_tpe_20260904_204003.briefing.md @@ -0,0 +1,67 @@ +# Optuna ๋ธŒ๋ฆฌํ•‘ โ€” ๊ผฌ๋ฆฌ (tpe) +๊ธฐ๊ฐ„: 2026-09-04 ~ 2026-09-04 (๊ฑฐ๋ž˜์ผโ‰ˆ1์ผ) ยท trials 200/200 +ํƒ์ƒ‰ ๊ฒŒ์ดํŠธ: WRโ‰ฅ0% PFโ‰ฅ0 ยท min_tradesโ‰ฅ1 | ํ›„๋ณด ๊ฒŒ์ดํŠธ: WRโ‰ฅ40% PFโ‰ฅ1 ยท min_tradesโ‰ฅ1 +- min_trades=1: **ํ•ฉ๊ฒฉ ์ธ์ • ์ตœ์†Œ ๊ฑฐ๋ž˜ ๊ฑด์ˆ˜**(ํ‘œ๋ณธ ๋ถ€์กฑยท์šฐ์—ฐ ์Šน๋ฅ  ๋ฐฉ์ง€). ์ด๋ณด๋‹ค ์ ์€ ์กฐํ•ฉ์€ ํ•™์Šต/ํ›„๋ณด ์ง‘๊ณ„์—์„œ ์ œ์™ธ๋ฉ๋‹ˆ๋‹ค. +ํ•™์Šต์šฉ ํ†ต๊ณผ 172๊ฑด ยท ์‚ฌํ›„ํ•ฉ๊ฒฉ(results_gated) 85๊ฑด + +## ๊ณผ์ ํ•ฉยท์ ์šฉ ๊ฐ€๋Šฅ๋„ (ํœด๋ฆฌ์Šคํ‹ฑ) +- **๊ณผ์ ํ•ฉ ์œ„ํ—˜ 40.0%** ยท **์ ์šฉ ๊ฐ€๋Šฅ๋„ 60.0%** ยท ํŒ์ •: **์ฃผ์˜** โ€” ์ ์šฉ ๊ฐ€๋Šฅ๋„ ์ค‘๊ฐ„ โ€” ๋‹ค์ผ(โ‰ฅ5์ผ) ์žฌ๊ฒ€์ฆยท์›น๋ฐฑํ…Œ ํ›„ ์†Œ์•ก๋งŒ + - ํ‘œ๋ณธ ์žฅ์ผ: +40.0p โ€” ๊ฑฐ๋ž˜์ผโ‰ˆ1์ผ โ€” ๋‹จ์ผ ์žฅ ๊ณผ์ ํ•ฉ ์œ„ํ—˜ ์ตœ๋Œ€ + - ๊ฑฐ๋ž˜ ํ‘œ๋ณธ: +0.0p โ€” ์ƒ์œ„ ํ›„๋ณด ๊ฑฐ๋ž˜ 114๊ฑด โ€” ์ƒ๋Œ€์  ์–‘ํ˜ธ + - ์Šน๋ฅ ยทPF ์ด์ƒ์น˜: +0.0p โ€” ์ด์ƒ์น˜ ์—†์Œ + - ๊ฒŒ์ดํŠธ ์ปค๋ฒ„: +0.0p โ€” ์‚ฌํ›„ํ•ฉ๊ฒฉ 85๊ฑด ยท stable 10๊ฑด + - PnL ๊ณ ์›: +0.0p โ€” ๊ณ ์› ๋น„์œจ 1% (1๊ฑด) +- ์ž„๊ณ„๊ฐ’ ๋ถ„ํฌ ํ‘œ๋ณธ: results_gated ์ƒ์œ„ 30๊ฑด +| ํŒŒ๋ผ๋ฏธํ„ฐ | median | p25~p75 | mode(๋น„์œจ) | +|---|---:|---|---| +| `entry_mode` | โ€” | โ€” | align (100%) | +| `cand_limit` | 20.0 | 20.0 ~ 20.0 | 20 (77%) | +| `max_daily_change` | 25.5 | 18.0 ~ 36.75 | 28.0 (10%) | +| `min_drop_rate` | 0.01 | 0.00625 ~ 0.015 | 0.005 (27%) | +| `min_recovery_ratio` | 0.11 | 0.09 ~ 0.1475 | 0.09 (20%) | +| `tail_ratio_min` | 1.2 | 0.825 ~ 1.3 | 1.3 (23%) | +| `tail_pct_min` | 0.003 | 0.002 ~ 0.0035 | 0.0035 (20%) | +| `max_rec_3m` | 0.81 | 0.7625 ~ 0.8725 | 0.77 (13%) | +| `shoulder_min_high` | 0.0065 | 0.004 ~ 0.009 | 0.009 (20%) | +| `shoulder_cut_pct` | 0.0015 | 0.0005 ~ 0.002 | 0.0005 (30%) | +| `stop_atr_mult` | 1.6 | 1.3 ~ 1.875 | 2.0 (10%) | +| `target_atr_mult` | 1.4 | 1.1 ~ 1.8 | 1.6 (13%) | +- _์ฐธ๊ณ : ๊ณผ์ ํ•ฉ%๋Š” ๊ต์ฐจ๊ฒ€์ฆ ์ ์ˆ˜๊ฐ€ ์•„๋‹ˆ๋ผ ํ‘œ๋ณธยท์ด์ƒ์น˜ยท๊ณ ์› ํœด๋ฆฌ์Šคํ‹ฑ์ž…๋‹ˆ๋‹ค. ์ ์šฉ ๊ฐ€๋Šฅ๋„%=100โˆ’๊ณผ์ ํ•ฉ์œ„ํ—˜%. DB ์ ์šฉ ๋ฒ„ํŠผ ํ™œ์„ฑ ์กฐ๊ฑด(gated PnL>0)๊ณผ๋Š” ๋ณ„๊ฐœ์ž…๋‹ˆ๋‹ค._ + +## ์ตœ์ข… ์„ ํƒ ํ›„๋ณด (๊ทœ์น™ ยท DB ์ ์šฉ ์ „ ํ™•์ธ) +- ์•„๋ž˜๋Š” **์—ญํ• ์ด ๋‹ค๋ฅธ** 4์ข… ํ›„๋ณด์ž…๋‹ˆ๋‹ค. mode Top10 1์œ„ โ‰  ์ต์ ˆ ๋Œ€ํ‘œ ยท **DB 1์ˆœ์œ„๋Š” ์‚ฌํ›„ํ•ฉ๊ฒฉ(gated)** ์ž…๋‹ˆ๋‹ค. +- mode pool: `positive` ยท scoring: `band_proximity_p25_p75` + +### ํ›„๋ณด 4์ข… +- **โ‘  ์‚ฌํ›„ํ•ฉ๊ฒฉ 1์œ„ (apply: gated)** (trial #137): PnL 86,259์› ยท WR 59.6% ยท PF 1.62 ยท ๊ฑฐ๋ž˜ 114๊ฑด ยท ์•ˆ์ •์ ์ˆ˜ -5168 ยท ํ˜ธ๊ฐ€OFF ยท ํœฉ์˜OFF +- **โ‘ก ์•ˆ์ • 1์œ„ (apply: stable)** (trial #34): PnL 20,926์› ยท WR 63.3% ยท PF 1.27 ยท ๊ฑฐ๋ž˜ 30๊ฑด ยท ์•ˆ์ •์ ์ˆ˜ 10128 ยท ํ˜ธ๊ฐ€OFF ยท ํœฉ์˜OFF +- **โ‘ข mode_combo (apply: mode)** (trial ์—†์Œ(์กฐ๋ฆฝ)): PnL -21,004์› ยท WR 57.4% ยท PF 0.79 ยท ๊ฑฐ๋ž˜ 528๊ฑด ยท ์•ˆ์ •์ ์ˆ˜ -19351 ยท ํ˜ธ๊ฐ€OFF ยท ํœฉ์˜OFF +- **โ‘ฃ mode Top10 1์œ„ (apply: consensus ยท ๋ฐด๋“œ ์ „ํ˜• trial)** (trial #91): PnL 45,239์› ยท WR 68.0% ยท PF 1.23 ยท ๊ฑฐ๋ž˜ 103๊ฑด ยท ์•ˆ์ •์ ์ˆ˜ -18704 ยท ๊ทผ์ ‘ 97.0% (45/52์ถ• ๋ฐด๋“œ์•ˆ) ยท ํ˜ธ๊ฐ€OFF ยท ํœฉ์˜OFF +- mode Top10 meta: pool 85๊ฑด ยท ์ถ• 52๊ฐœ + +### ์ถ”์ฒœ (์ž๋™ ยท confirm ํ•„์ˆ˜) +1. **์‹ค๋งค DB ์ ์šฉ 1์ˆœ์œ„ โ†’ โ‘  ์‚ฌํ›„ํ•ฉ๊ฒฉ 1์œ„** (`optunaApply gated`) โ€” WR/PFยทmin_trades ์‚ฌํ›„ ํ†ต๊ณผ. +2. **๋ณ€๋™์„ฑยท์†์‹ค์ผ ์ค„์ด๊ธฐ โ†’ โ‘ก ์•ˆ์ • 1์œ„** (`stable`) โ€” PnL๋ณด๋‹ค ์ผ๋ณ„ ์•ˆ์ • ์šฐ์„  ์‹œ. +3. **2์ฐจ narrowยท๋Œ€ํ‘œ ์ˆซ์ž โ†’ โ‘ข mode_combo** โ€” ์ถ•๋ณ„ ์ตœ๋นˆ ์กฐ๋ฆฝ ยท trial ๋ฒˆํ˜ธ ์—†์Œ ยท ์ต์ ˆ์€ pool ์ตœ๋นˆ๊ฐ’ ์ฐธ๊ณ . +4. **โ‘ฃ mode Top10 1์œ„** โ€” ์–‘์ˆ˜ pool ์ „ํ˜• trial(๋‹ค์ถ• ๋ฐด๋“œ ๊ทผ์ ‘). **์ต์ ˆ ํ•˜๋‚˜๋กœ ์“ฐ์ง€ ๋ง ๊ฒƒ** ยท ํ‘œ์—์„œ ใ€Œ๋ณด๊ธฐใ€โ†’ consensus apply. + +## ์ด์ „ ์žฅ์—์„œ๋Š” +- ์‹ค๋งค ๋™๊ธฐ๊ฐ„ ์ฒญ์‚ฐ 8๊ฑด ยท ์Šน๋ฅ  50% ยท ํ•ฉ์‚ฐ PnL 121,682์› (๋ฐฑํ…Œ Optuna์™€ ์ˆซ์ž ๋‹ฌ๋ผ๋„ ์ •์ƒ โ€” ๊ณ ์ŠคํŠธยท์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑ ๊ฒฝ๋กœ ์ฐจ์ด). +- ์‚ฌํ›„ํ•ฉ๊ฒฉ 1์œ„: trial #137 ยท ๊ฑฐ๋ž˜ 114๊ฑด ยท ์Šน๋ฅ  59.6% ยท PF 1.62 ยท PnL 86,259์› +- ํ‘œ๋ณธ ์žฅ์ด 1์ผ๋ฟ์ด๋ผ, โ€˜์ด์ „ ์žฅ์— ์ž˜ ๋จนํžŒ ์ˆซ์žโ€™์ผ ๋ฟ **์ถ”์„ธ๊ฐ€ ๋ฐ”๋€Œ๋ฉด ๋ฐ”๋กœ ๊นจ์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.** + +## ์•ž์œผ๋กœ ์žฅ์—์„œ๋Š” +- **1~2์ผ Optuna best๋ฅผ ๋ฐ”๋กœ ์‹ค๋งค์— ๋„ฃ์ง€ ๋งˆ์„ธ์š”.** ๋‹ค์ผ(โ‰ฅ5๊ฑฐ๋ž˜์ผ) ์žฌ๊ฒ€์ฆยท์›น๋ฐฑํ…Œ 1ํšŒ ํ›„ ๊ฒ€ํ† . +- ์ ์šฉ ์‹œ์—๋Š” `results_gated` ํ›„๋ณด๋งŒ. ํƒ์ƒ‰์šฉ best(objective)์™€ ๋‹ค๋ฅผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. +- ์žฅ์ด ์ข์•„์ง€๊ฑฐ๋‚˜ ๋ณ€๋™์„ฑ์ด ์ปค์ง€๋ฉด: ์†์ ˆยทํŠธ๋ ˆ์ผยท์‹œ๊ฐ„์ฐฝ์ด ๋จผ์ € ๊นจ์ง‘๋‹ˆ๋‹ค. ์Šน๋ฅ  ์ž๋ž‘๋ณด๋‹ค **์†์ ˆ์ด ์‚ด์•„ ์žˆ๋Š”์ง€**๋ฅผ ๋ณด์„ธ์š”. +- ์‚ฌํ›„ํ•ฉ๊ฒฉ์ด ์žˆ์–ด๋„ โ€˜๋‚ด์ผ๋„ ๊ฐ™์€ ์žฅโ€™์ด ์•„๋‹™๋‹ˆ๋‹ค. ํŽ˜์ดํผ/์†Œ์•กยท๋ชจ์˜๋กœ 1~2์ผ ๊ด€์ฐฐ ํ›„ ํ™•๋Œ€ํ•˜์„ธ์š”. + +_์ƒ์„ฑ: 2026-09-04 20:40:05 (rule)_ + +## AI ์ฝ”๋ฉ˜ํŠธ (์ด์ „ ์žฅ / ์•ž์œผ๋กœ ์žฅ) [gemini] + +## ์ด์ „ ์žฅ์—์„œ๋Š” +์‹ค๋งค์—์„œ๋Š” ๋™๊ธฐ๊ฐ„ 8๊ฑด ์ฒญ์‚ฐ์œผ๋กœ ์Šน๋ฅ  50%, ํ•ฉ์‚ฐ PnL 121,682์›์„ ๊ธฐ๋กํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š” ๋ฐฑํ…Œ์ŠคํŠธ(Optuna) ๊ฒฐ๊ณผ์™€ ์ˆซ์ž๊ฐ€ ๋‹ค๋ฅผ ์ˆ˜ ์žˆ๋Š”๋ฐ, ๊ณ ์ŠคํŠธ ์˜ค๋”, ์œ ๋‹ˆ๋ฒ„์Šค, ํ‹ฑ ๋ฐ์ดํ„ฐ ๊ฒฝ๋กœ ์ฐจ์ด ๋“ฑ์œผ๋กœ ์ธํ•œ ์ •์ƒ์ ์ธ ํ˜„์ƒ์ž…๋‹ˆ๋‹ค. ๋ฐฑํ…Œ์ŠคํŠธ์—์„œ๋Š” ์‚ฌํ›„ํ•ฉ๊ฒฉ(gated) 1์œ„๊ฐ€ trial #137๋ฒˆ์œผ๋กœ, ๊ฑฐ๋ž˜ 114๊ฑด, ์Šน๋ฅ  59.6%, PF 1.62, PnL 86,259์›์˜ ์„ฑ๊ณผ๋ฅผ ๋ณด์˜€์Šต๋‹ˆ๋‹ค. + +## ์•ž์œผ๋กœ ์žฅ์—์„œ๋Š” +์ด๋ฒˆ Optuna ๊ฒฐ๊ณผ๋Š” ๋‹จ ํ•˜๋ฃจ์น˜ ๊ฑฐ๋ž˜ ๋ฐ์ดํ„ฐ๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ์ตœ์ ํ™”๋˜์—ˆ๊ธฐ์—, ๊ณผ์ ํ•ฉ ์œ„ํ—˜(40%)์ด ๋งค์šฐ ๋†’์Šต๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ์‚ฌํ›„ํ•ฉ๊ฒฉ 1์œ„๋ผ ํ•ด๋„ ํŠน์ • ์žฅ์„ธ์—๋งŒ ์šฐ์—ฐํžˆ ๋งž์•˜์„ ๊ฐ€๋Šฅ์„ฑ์ด ํฝ๋‹ˆ๋‹ค. ๊ณง๋ฐ”๋กœ ์‹ค๋งค์— ์ ์šฉํ•˜๊ธฐ๋ณด๋‹ค๋Š”, ์ตœ์†Œ 5๊ฑฐ๋ž˜์ผ ์ด์ƒ ๋‹ค์ผ ์žฌ๊ฒ€์ฆ๊ณผ ๋ชจ์˜ ํˆฌ์ž๋ฅผ ํ†ตํ•ด ๋ฐฑํ…Œ์ŠคํŠธ์™€ ์‹ค๋งค์˜ ๊ดด๋ฆฌ(๊ณ ์ŠคํŠธ, ์œ ๋‹ˆ๋ฒ„์Šค, ํ‹ฑ ๊ฒฝ๋กœ ์ฐจ์ด)๋ฅผ ํ™•์ธํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ใ€Œmode Top10 1์œ„ใ€๋Š” ์ต์ ˆ ๋Œ€ํ‘œ๊ฐ€ ์•„๋‹ˆ๋ฉฐ, ๋‹จ์ˆœํžˆ ํŒŒ๋ผ๋ฏธํ„ฐ ๋ฐด๋“œ ๊ทผ์ ‘ ์กฐํ•ฉ์ž…๋‹ˆ๋‹ค. ์–ด๋–ค ์ข…๋ชฉ๋„ ํ™•์ • ์ˆ˜์ต์„ ์•ฝ์†ํ•  ์ˆ˜ ์—†์œผ๋‹ˆ, ์‹œ์žฅ ๋ณ€๋™์„ฑ ํ™•๋Œ€ ์‹œ ํ‘œ๋ณธ ๋ถ€์กฑ ๋ฐ ์†์‹ค ๊ด€๋ฆฌ์— ๊ฐ๋ณ„ํžˆ ์œ ์˜ํ•˜๋ฉฐ ์†Œ์•ก์œผ๋กœ ๊ด€์ฐฐ์„ ์‹œ์ž‘ํ•˜์„ธ์š”. diff --git a/kis_trader/backtest/results/optuna_tail_tpe_20260904_204420.briefing.md b/kis_trader/backtest/results/optuna_tail_tpe_20260904_204420.briefing.md new file mode 100644 index 0000000..b96cb0f --- /dev/null +++ b/kis_trader/backtest/results/optuna_tail_tpe_20260904_204420.briefing.md @@ -0,0 +1,69 @@ +# Optuna ๋ธŒ๋ฆฌํ•‘ โ€” ๊ผฌ๋ฆฌ (tpe) +๊ธฐ๊ฐ„: 2026-09-04 ~ 2026-09-04 (๊ฑฐ๋ž˜์ผโ‰ˆ1์ผ) ยท trials 200/200 +ํƒ์ƒ‰ ๊ฒŒ์ดํŠธ: WRโ‰ฅ0% PFโ‰ฅ0 ยท min_tradesโ‰ฅ1 | ํ›„๋ณด ๊ฒŒ์ดํŠธ: WRโ‰ฅ40% PFโ‰ฅ1 ยท min_tradesโ‰ฅ1 +- min_trades=1: **ํ•ฉ๊ฒฉ ์ธ์ • ์ตœ์†Œ ๊ฑฐ๋ž˜ ๊ฑด์ˆ˜**(ํ‘œ๋ณธ ๋ถ€์กฑยท์šฐ์—ฐ ์Šน๋ฅ  ๋ฐฉ์ง€). ์ด๋ณด๋‹ค ์ ์€ ์กฐํ•ฉ์€ ํ•™์Šต/ํ›„๋ณด ์ง‘๊ณ„์—์„œ ์ œ์™ธ๋ฉ๋‹ˆ๋‹ค. +ํ•™์Šต์šฉ ํ†ต๊ณผ 147๊ฑด ยท ์‚ฌํ›„ํ•ฉ๊ฒฉ(results_gated) 47๊ฑด + +## ๊ณผ์ ํ•ฉยท์ ์šฉ ๊ฐ€๋Šฅ๋„ (ํœด๋ฆฌ์Šคํ‹ฑ) +- **๊ณผ์ ํ•ฉ ์œ„ํ—˜ 40.0%** ยท **์ ์šฉ ๊ฐ€๋Šฅ๋„ 60.0%** ยท ํŒ์ •: **์ฃผ์˜** โ€” ์ ์šฉ ๊ฐ€๋Šฅ๋„ ์ค‘๊ฐ„ โ€” ๋‹ค์ผ(โ‰ฅ5์ผ) ์žฌ๊ฒ€์ฆยท์›น๋ฐฑํ…Œ ํ›„ ์†Œ์•ก๋งŒ + - ํ‘œ๋ณธ ์žฅ์ผ: +40.0p โ€” ๊ฑฐ๋ž˜์ผโ‰ˆ1์ผ โ€” ๋‹จ์ผ ์žฅ ๊ณผ์ ํ•ฉ ์œ„ํ—˜ ์ตœ๋Œ€ + - ๊ฑฐ๋ž˜ ํ‘œ๋ณธ: +0.0p โ€” ์ƒ์œ„ ํ›„๋ณด ๊ฑฐ๋ž˜ 93๊ฑด โ€” ์ƒ๋Œ€์  ์–‘ํ˜ธ + - ์Šน๋ฅ ยทPF ์ด์ƒ์น˜: +0.0p โ€” ์ด์ƒ์น˜ ์—†์Œ + - ๊ฒŒ์ดํŠธ ์ปค๋ฒ„: +0.0p โ€” ์‚ฌํ›„ํ•ฉ๊ฒฉ 47๊ฑด ยท stable 10๊ฑด + - PnL ๊ณ ์›: +0.0p โ€” ๊ณ ์› ๋น„์œจ 2% (1๊ฑด) +- ์ž„๊ณ„๊ฐ’ ๋ถ„ํฌ ํ‘œ๋ณธ: results_gated ์ƒ์œ„ 30๊ฑด +| ํŒŒ๋ผ๋ฏธํ„ฐ | median | p25~p75 | mode(๋น„์œจ) | +|---|---:|---|---| +| `entry_mode` | โ€” | โ€” | limit_atr (100%) | +| `cand_limit` | 20.0 | 20.0 ~ 20.0 | 20 (80%) | +| `max_daily_change` | 23.5 | 16.0 ~ 33.25 | 16.0 (10%) | +| `min_drop_rate` | 0.0175 | 0.01 ~ 0.025 | 0.005 (23%) | +| `min_recovery_ratio` | 0.13 | 0.11 ~ 0.1875 | 0.13 (17%) | +| `tail_ratio_min` | 1.25 | 1.1 ~ 1.375 | 1.3 (23%) | +| `tail_pct_min` | 0.003 | 0.002125 ~ 0.004375 | 0.003 (20%) | +| `max_rec_3m` | 0.87 | 0.85 ~ 0.92 | 0.85 (13%) | +| `shoulder_min_high` | 0.003 | 0.002 ~ 0.004 | 0.003 (33%) | +| `shoulder_cut_pct` | 0.0015 | 0.001 ~ 0.0025 | 0.0015 (23%) | +| `stop_atr_mult` | 2.0 | 1.725 ~ 2.275 | 2.0 (13%) | +| `target_atr_mult` | 2.95 | 2.7 ~ 3.2 | 2.7 (20%) | +- _์ฐธ๊ณ : ๊ณผ์ ํ•ฉ%๋Š” ๊ต์ฐจ๊ฒ€์ฆ ์ ์ˆ˜๊ฐ€ ์•„๋‹ˆ๋ผ ํ‘œ๋ณธยท์ด์ƒ์น˜ยท๊ณ ์› ํœด๋ฆฌ์Šคํ‹ฑ์ž…๋‹ˆ๋‹ค. ์ ์šฉ ๊ฐ€๋Šฅ๋„%=100โˆ’๊ณผ์ ํ•ฉ์œ„ํ—˜%. DB ์ ์šฉ ๋ฒ„ํŠผ ํ™œ์„ฑ ์กฐ๊ฑด(gated PnL>0)๊ณผ๋Š” ๋ณ„๊ฐœ์ž…๋‹ˆ๋‹ค._ + +## ์ตœ์ข… ์„ ํƒ ํ›„๋ณด (๊ทœ์น™ ยท DB ์ ์šฉ ์ „ ํ™•์ธ) +- ์•„๋ž˜๋Š” **์—ญํ• ์ด ๋‹ค๋ฅธ** 4์ข… ํ›„๋ณด์ž…๋‹ˆ๋‹ค. mode Top10 1์œ„ โ‰  ์ต์ ˆ ๋Œ€ํ‘œ ยท **DB 1์ˆœ์œ„๋Š” ์‚ฌํ›„ํ•ฉ๊ฒฉ(gated)** ์ž…๋‹ˆ๋‹ค. +- mode pool: `positive` ยท scoring: `band_proximity_p25_p75` + +### ํ›„๋ณด 4์ข… +- **โ‘  ์‚ฌํ›„ํ•ฉ๊ฒฉ 1์œ„ (apply: gated)** (trial #186): PnL 81,884์› ยท WR 73.1% ยท PF 1.87 ยท ๊ฑฐ๋ž˜ 93๊ฑด ยท ์•ˆ์ •์ ์ˆ˜ 4219 ยท ํ˜ธ๊ฐ€OFF ยท ํœฉ์˜OFF +- **โ‘ก ์•ˆ์ • 1์œ„ (apply: stable)** (trial #79): PnL 18,967์› ยท WR 54.2% ยท PF 1.36 ยท ๊ฑฐ๋ž˜ 24๊ฑด ยท ์•ˆ์ •์ ์ˆ˜ 7219 ยท ํ˜ธ๊ฐ€ON spr2.1 r0.20 askร—67 ยท ํœฉ์˜OFF +- **โ‘ข mode_combo (apply: mode)** (trial ์—†์Œ(์กฐ๋ฆฝ)): PnL -16,721์› ยท WR 65.9% ยท PF 0.84 ยท ๊ฑฐ๋ž˜ 1172๊ฑด ยท ์•ˆ์ •์ ์ˆ˜ -15988 ยท ํ˜ธ๊ฐ€ON spr1.7 r0.15 askร—55 ยท ํœฉ์˜OFF +- **โ‘ฃ mode Top10 1์œ„ (apply: consensus ยท ๋ฐด๋“œ ์ „ํ˜• trial)** (trial #88): PnL 19,628์› ยท WR 61.4% ยท PF 1.10 ยท ๊ฑฐ๋ž˜ 171๊ฑด ยท ์•ˆ์ •์ ์ˆ˜ -5547 ยท ๊ทผ์ ‘ 97.5% (45/53์ถ• ๋ฐด๋“œ์•ˆ) ยท ํ˜ธ๊ฐ€ON spr3.9 r0.20 askร—72 ยท ํœฉ์˜OFF +- mode Top10 meta: pool 48๊ฑด ยท ์ถ• 53๊ฐœ + +### ์ถ”์ฒœ (์ž๋™ ยท confirm ํ•„์ˆ˜) +1. **์‹ค๋งค DB ์ ์šฉ 1์ˆœ์œ„ โ†’ โ‘  ์‚ฌํ›„ํ•ฉ๊ฒฉ 1์œ„** (`optunaApply gated`) โ€” WR/PFยทmin_trades ์‚ฌํ›„ ํ†ต๊ณผ. +2. **๋ณ€๋™์„ฑยท์†์‹ค์ผ ์ค„์ด๊ธฐ โ†’ โ‘ก ์•ˆ์ • 1์œ„** (`stable`) โ€” PnL๋ณด๋‹ค ์ผ๋ณ„ ์•ˆ์ • ์šฐ์„  ์‹œ. +3. **2์ฐจ narrowยท๋Œ€ํ‘œ ์ˆซ์ž โ†’ โ‘ข mode_combo** โ€” ์ถ•๋ณ„ ์ตœ๋นˆ ์กฐ๋ฆฝ ยท trial ๋ฒˆํ˜ธ ์—†์Œ ยท ์ต์ ˆ์€ pool ์ตœ๋นˆ๊ฐ’ ์ฐธ๊ณ . +4. **โ‘ฃ mode Top10 1์œ„** โ€” ์–‘์ˆ˜ pool ์ „ํ˜• trial(๋‹ค์ถ• ๋ฐด๋“œ ๊ทผ์ ‘). **์ต์ ˆ ํ•˜๋‚˜๋กœ ์“ฐ์ง€ ๋ง ๊ฒƒ** ยท ํ‘œ์—์„œ ใ€Œ๋ณด๊ธฐใ€โ†’ consensus apply. + +## ์ด์ „ ์žฅ์—์„œ๋Š” +- ์‹ค๋งค ๋™๊ธฐ๊ฐ„ ์ฒญ์‚ฐ 8๊ฑด ยท ์Šน๋ฅ  50% ยท ํ•ฉ์‚ฐ PnL 121,682์› (๋ฐฑํ…Œ Optuna์™€ ์ˆซ์ž ๋‹ฌ๋ผ๋„ ์ •์ƒ โ€” ๊ณ ์ŠคํŠธยท์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑ ๊ฒฝ๋กœ ์ฐจ์ด). +- ์‚ฌํ›„ํ•ฉ๊ฒฉ 1์œ„: trial #186 ยท ๊ฑฐ๋ž˜ 93๊ฑด ยท ์Šน๋ฅ  73.1% ยท PF 1.87 ยท PnL 81,884์› +- ํ‘œ๋ณธ ์žฅ์ด 1์ผ๋ฟ์ด๋ผ, โ€˜์ด์ „ ์žฅ์— ์ž˜ ๋จนํžŒ ์ˆซ์žโ€™์ผ ๋ฟ **์ถ”์„ธ๊ฐ€ ๋ฐ”๋€Œ๋ฉด ๋ฐ”๋กœ ๊นจ์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.** + +## ์•ž์œผ๋กœ ์žฅ์—์„œ๋Š” +- **1~2์ผ Optuna best๋ฅผ ๋ฐ”๋กœ ์‹ค๋งค์— ๋„ฃ์ง€ ๋งˆ์„ธ์š”.** ๋‹ค์ผ(โ‰ฅ5๊ฑฐ๋ž˜์ผ) ์žฌ๊ฒ€์ฆยท์›น๋ฐฑํ…Œ 1ํšŒ ํ›„ ๊ฒ€ํ† . +- ์ ์šฉ ์‹œ์—๋Š” `results_gated` ํ›„๋ณด๋งŒ. ํƒ์ƒ‰์šฉ best(objective)์™€ ๋‹ค๋ฅผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. +- ์žฅ์ด ์ข์•„์ง€๊ฑฐ๋‚˜ ๋ณ€๋™์„ฑ์ด ์ปค์ง€๋ฉด: ์†์ ˆยทํŠธ๋ ˆ์ผยท์‹œ๊ฐ„์ฐฝ์ด ๋จผ์ € ๊นจ์ง‘๋‹ˆ๋‹ค. ์Šน๋ฅ  ์ž๋ž‘๋ณด๋‹ค **์†์ ˆ์ด ์‚ด์•„ ์žˆ๋Š”์ง€**๋ฅผ ๋ณด์„ธ์š”. +- ์‚ฌํ›„ํ•ฉ๊ฒฉ์ด ์žˆ์–ด๋„ โ€˜๋‚ด์ผ๋„ ๊ฐ™์€ ์žฅโ€™์ด ์•„๋‹™๋‹ˆ๋‹ค. ํŽ˜์ดํผ/์†Œ์•กยท๋ชจ์˜๋กœ 1~2์ผ ๊ด€์ฐฐ ํ›„ ํ™•๋Œ€ํ•˜์„ธ์š”. + +_์ƒ์„ฑ: 2026-09-04 20:44:22 (rule)_ + +## AI ์ฝ”๋ฉ˜ํŠธ (์ด์ „ ์žฅ / ์•ž์œผ๋กœ ์žฅ) [gemini] + +## ์ด์ „ ์žฅ์—์„œ๋Š” + +Optuna TPE ๋ฐฑํ…Œ์ŠคํŠธ ๊ฒฐ๊ณผ, ์‚ฌํ›„ํ•ฉ๊ฒฉ๋œ ์ „๋žต ์ค‘ PnL 81,884์›, ์Šน๋ฅ  73.1%์˜ trial #186์ด ๊ฐ€์žฅ ์ข‹์•˜์Šต๋‹ˆ๋‹ค. ์‹ค์ œ ๋งค๋งค PnL(121,682์›)๊ณผ ๋ฐฑํ…Œ์ŠคํŠธ ๊ฐ„ ์ฐจ์ด๋Š” ๊ณ ์ŠคํŠธํผ์ง€ ๋“ฑ์œผ๋กœ ์ธํ•œ ์ •์ƒ ๋ฒ”์œ„ ๋‚ด์ด๋ฉฐ, ํ‘œ๋ณธ์ผ์ด 1์ผ๋ฟ์ด๋ผ 'ํŠน์ • ์žฅ์— ์ž˜ ๋งž์•˜๋˜ ์ˆซ์ž'์ผ ๋ฟ ๊ณผ์ ํ•ฉ ์œ„ํ—˜์ด ๋งค์šฐ ๋†’๋‹ค๋Š” ์ ์„ ๊ฒฝ๊ณ ํ•ฉ๋‹ˆ๋‹ค. + +## ์•ž์œผ๋กœ ์žฅ์—์„œ๋Š” + +1์ผ ๋ฐฑํ…Œ์ŠคํŠธ ๊ฒฐ๊ณผ๋งŒ์œผ๋กœ ๊ณง๋ฐ”๋กœ ์‹ค๋งค ์ ์šฉ์€ ๊ธˆ๋ฌผ์ž…๋‹ˆ๋‹ค. ๊ณผ์ ํ•ฉ ์œ„ํ—˜์ด ๋†’์•„ ๋‹ค์ผ(โ‰ฅ5๊ฑฐ๋ž˜์ผ) ์žฌ๊ฒ€์ฆ, ์›น๋ฐฑํ…Œ์ŠคํŠธ ํ›„ ์†Œ์•ก์œผ๋กœ ๊ด€์ฐฐํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๋ฐฑํ…Œ์ŠคํŠธ์™€ ์‹ค๋งค ๊ฐ„ ๊ณ ์ŠคํŠธํผ์ง€ ๋“ฑ ๊ดด๋ฆฌ๊ฐ€ ํฌ๊ณ , ์‹œ์žฅ ๋ณ€ํ™” ์‹œ ์†์ ˆ์ด ๋จผ์ € ๊นจ์งˆ ์ˆ˜ ์žˆ์œผ๋‹ˆ ์Šน๋ฅ ๋ณด๋‹ค ์†์ ˆ ์ž‘๋™ ์—ฌ๋ถ€ ํ™•์ธ์ด ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค. ํŠน์ • ์ข…๋ชฉ ๋งค์ˆ˜ ์ถ”์ฒœ์ด๋‚˜ ํ™•์ • ์ˆ˜์ต ์•ฝ์†์€ ๋ถˆ๊ฐ€ํ•ฉ๋‹ˆ๋‹ค. diff --git a/kis_trader/backtest/results/optuna_tail_tpe_20260904_204902.briefing.md b/kis_trader/backtest/results/optuna_tail_tpe_20260904_204902.briefing.md new file mode 100644 index 0000000..f114da4 --- /dev/null +++ b/kis_trader/backtest/results/optuna_tail_tpe_20260904_204902.briefing.md @@ -0,0 +1,69 @@ +# Optuna ๋ธŒ๋ฆฌํ•‘ โ€” ๊ผฌ๋ฆฌ (tpe) +๊ธฐ๊ฐ„: 2026-09-04 ~ 2026-09-04 (๊ฑฐ๋ž˜์ผโ‰ˆ1์ผ) ยท trials 200/200 +ํƒ์ƒ‰ ๊ฒŒ์ดํŠธ: WRโ‰ฅ0% PFโ‰ฅ0 ยท min_tradesโ‰ฅ1 | ํ›„๋ณด ๊ฒŒ์ดํŠธ: WRโ‰ฅ40% PFโ‰ฅ1 ยท min_tradesโ‰ฅ1 +- min_trades=1: **ํ•ฉ๊ฒฉ ์ธ์ • ์ตœ์†Œ ๊ฑฐ๋ž˜ ๊ฑด์ˆ˜**(ํ‘œ๋ณธ ๋ถ€์กฑยท์šฐ์—ฐ ์Šน๋ฅ  ๋ฐฉ์ง€). ์ด๋ณด๋‹ค ์ ์€ ์กฐํ•ฉ์€ ํ•™์Šต/ํ›„๋ณด ์ง‘๊ณ„์—์„œ ์ œ์™ธ๋ฉ๋‹ˆ๋‹ค. +ํ•™์Šต์šฉ ํ†ต๊ณผ 171๊ฑด ยท ์‚ฌํ›„ํ•ฉ๊ฒฉ(results_gated) 73๊ฑด + +## ๊ณผ์ ํ•ฉยท์ ์šฉ ๊ฐ€๋Šฅ๋„ (ํœด๋ฆฌ์Šคํ‹ฑ) +- **๊ณผ์ ํ•ฉ ์œ„ํ—˜ 40.0%** ยท **์ ์šฉ ๊ฐ€๋Šฅ๋„ 60.0%** ยท ํŒ์ •: **์ฃผ์˜** โ€” ์ ์šฉ ๊ฐ€๋Šฅ๋„ ์ค‘๊ฐ„ โ€” ๋‹ค์ผ(โ‰ฅ5์ผ) ์žฌ๊ฒ€์ฆยท์›น๋ฐฑํ…Œ ํ›„ ์†Œ์•ก๋งŒ + - ํ‘œ๋ณธ ์žฅ์ผ: +40.0p โ€” ๊ฑฐ๋ž˜์ผโ‰ˆ1์ผ โ€” ๋‹จ์ผ ์žฅ ๊ณผ์ ํ•ฉ ์œ„ํ—˜ ์ตœ๋Œ€ + - ๊ฑฐ๋ž˜ ํ‘œ๋ณธ: +0.0p โ€” ์ƒ์œ„ ํ›„๋ณด ๊ฑฐ๋ž˜ 104๊ฑด โ€” ์ƒ๋Œ€์  ์–‘ํ˜ธ + - ์Šน๋ฅ ยทPF ์ด์ƒ์น˜: +0.0p โ€” ์ด์ƒ์น˜ ์—†์Œ + - ๊ฒŒ์ดํŠธ ์ปค๋ฒ„: +0.0p โ€” ์‚ฌํ›„ํ•ฉ๊ฒฉ 73๊ฑด ยท stable 10๊ฑด + - PnL ๊ณ ์›: +0.0p โ€” ๊ณ ์› ๋น„์œจ 1% (1๊ฑด) +- ์ž„๊ณ„๊ฐ’ ๋ถ„ํฌ ํ‘œ๋ณธ: results_gated ์ƒ์œ„ 30๊ฑด +| ํŒŒ๋ผ๋ฏธํ„ฐ | median | p25~p75 | mode(๋น„์œจ) | +|---|---:|---|---| +| `entry_mode` | โ€” | โ€” | limit_atr (100%) | +| `cand_limit` | 0.0 | 0.0 ~ 0.0 | 0 (77%) | +| `max_daily_change` | 25.5 | 16.5 ~ 35.75 | 21.0 (13%) | +| `min_drop_rate` | 0.02 | 0.01 ~ 0.02 | 0.02 (37%) | +| `min_recovery_ratio` | 0.13 | 0.1025 ~ 0.15 | 0.14 (13%) | +| `tail_ratio_min` | 0.85 | 0.7 ~ 1.0 | 1.0 (27%) | +| `tail_pct_min` | 0.0025 | 0.001625 ~ 0.003 | 0.003 (27%) | +| `max_rec_3m` | 0.855 | 0.785 ~ 0.8975 | 0.87 (13%) | +| `shoulder_min_high` | 0.009 | 0.008 ~ 0.01 | 0.01 (23%) | +| `shoulder_cut_pct` | 0.001 | 0.0005 ~ 0.0015 | 0.001 (33%) | +| `stop_atr_mult` | 2.55 | 2.025 ~ 2.85 | 3.0 (13%) | +| `target_atr_mult` | 3.15 | 2.475 ~ 3.4 | 3.5 (20%) | +- _์ฐธ๊ณ : ๊ณผ์ ํ•ฉ%๋Š” ๊ต์ฐจ๊ฒ€์ฆ ์ ์ˆ˜๊ฐ€ ์•„๋‹ˆ๋ผ ํ‘œ๋ณธยท์ด์ƒ์น˜ยท๊ณ ์› ํœด๋ฆฌ์Šคํ‹ฑ์ž…๋‹ˆ๋‹ค. ์ ์šฉ ๊ฐ€๋Šฅ๋„%=100โˆ’๊ณผ์ ํ•ฉ์œ„ํ—˜%. DB ์ ์šฉ ๋ฒ„ํŠผ ํ™œ์„ฑ ์กฐ๊ฑด(gated PnL>0)๊ณผ๋Š” ๋ณ„๊ฐœ์ž…๋‹ˆ๋‹ค._ + +## ์ตœ์ข… ์„ ํƒ ํ›„๋ณด (๊ทœ์น™ ยท DB ์ ์šฉ ์ „ ํ™•์ธ) +- ์•„๋ž˜๋Š” **์—ญํ• ์ด ๋‹ค๋ฅธ** 4์ข… ํ›„๋ณด์ž…๋‹ˆ๋‹ค. mode Top10 1์œ„ โ‰  ์ต์ ˆ ๋Œ€ํ‘œ ยท **DB 1์ˆœ์œ„๋Š” ์‚ฌํ›„ํ•ฉ๊ฒฉ(gated)** ์ž…๋‹ˆ๋‹ค. +- mode pool: `positive` ยท scoring: `band_proximity_p25_p75` + +### ํ›„๋ณด 4์ข… +- **โ‘  ์‚ฌํ›„ํ•ฉ๊ฒฉ 1์œ„ (apply: gated)** (trial #165): PnL 51,970์› ยท WR 61.5% ยท PF 1.21 ยท ๊ฑฐ๋ž˜ 104๊ฑด ยท ์•ˆ์ •์ ์ˆ˜ -12101 ยท ํ˜ธ๊ฐ€OFF ยท ํœฉ์˜ON sub30s lb120s dip0.30% tol0.20% +- **โ‘ก ์•ˆ์ • 1์œ„ (apply: stable)** (trial #22): PnL 6,587์› ยท WR 60.0% ยท PF 1.45 ยท ๊ฑฐ๋ž˜ 5๊ฑด ยท ์•ˆ์ •์ ์ˆ˜ 2945 ยท ํ˜ธ๊ฐ€OFF ยท ํœฉ์˜ON sub60s lb60s dip0.90% tol0.15% +- **โ‘ข mode_combo (apply: mode)** (trial ์—†์Œ(์กฐ๋ฆฝ)): PnL -1,603์› ยท WR 60.3% ยท PF 0.81 ยท ๊ฑฐ๋ž˜ 58๊ฑด ยท ์•ˆ์ •์ ์ˆ˜ -986 ยท ํ˜ธ๊ฐ€ON spr5.7 r1.00 askร—76 ยท ํœฉ์˜ON sub45s lb90s dip0.20% tol0.10% +- **โ‘ฃ mode Top10 1์œ„ (apply: consensus ยท ๋ฐด๋“œ ์ „ํ˜• trial)** (trial #151): PnL 16,904์› ยท WR 61.3% ยท PF 1.21 ยท ๊ฑฐ๋ž˜ 31๊ฑด ยท ์•ˆ์ •์ ์ˆ˜ -7018 ยท ๊ทผ์ ‘ 96.5% (44/53์ถ• ๋ฐด๋“œ์•ˆ) ยท ํ˜ธ๊ฐ€OFF ยท ํœฉ์˜ON sub30s lb90s dip0.30% tol0.15% +- mode Top10 meta: pool 73๊ฑด ยท ์ถ• 53๊ฐœ + +### ์ถ”์ฒœ (์ž๋™ ยท confirm ํ•„์ˆ˜) +1. **์‹ค๋งค DB ์ ์šฉ 1์ˆœ์œ„ โ†’ โ‘  ์‚ฌํ›„ํ•ฉ๊ฒฉ 1์œ„** (`optunaApply gated`) โ€” WR/PFยทmin_trades ์‚ฌํ›„ ํ†ต๊ณผ. +2. **๋ณ€๋™์„ฑยท์†์‹ค์ผ ์ค„์ด๊ธฐ โ†’ โ‘ก ์•ˆ์ • 1์œ„** (`stable`) โ€” PnL๋ณด๋‹ค ์ผ๋ณ„ ์•ˆ์ • ์šฐ์„  ์‹œ. +3. **2์ฐจ narrowยท๋Œ€ํ‘œ ์ˆซ์ž โ†’ โ‘ข mode_combo** โ€” ์ถ•๋ณ„ ์ตœ๋นˆ ์กฐ๋ฆฝ ยท trial ๋ฒˆํ˜ธ ์—†์Œ ยท ์ต์ ˆ์€ pool ์ตœ๋นˆ๊ฐ’ ์ฐธ๊ณ . +4. **โ‘ฃ mode Top10 1์œ„** โ€” ์–‘์ˆ˜ pool ์ „ํ˜• trial(๋‹ค์ถ• ๋ฐด๋“œ ๊ทผ์ ‘). **์ต์ ˆ ํ•˜๋‚˜๋กœ ์“ฐ์ง€ ๋ง ๊ฒƒ** ยท ํ‘œ์—์„œ ใ€Œ๋ณด๊ธฐใ€โ†’ consensus apply. + +## ์ด์ „ ์žฅ์—์„œ๋Š” +- ์‹ค๋งค ๋™๊ธฐ๊ฐ„ ์ฒญ์‚ฐ 8๊ฑด ยท ์Šน๋ฅ  50% ยท ํ•ฉ์‚ฐ PnL 121,682์› (๋ฐฑํ…Œ Optuna์™€ ์ˆซ์ž ๋‹ฌ๋ผ๋„ ์ •์ƒ โ€” ๊ณ ์ŠคํŠธยท์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑ ๊ฒฝ๋กœ ์ฐจ์ด). +- ์‚ฌํ›„ํ•ฉ๊ฒฉ 1์œ„: trial #165 ยท ๊ฑฐ๋ž˜ 104๊ฑด ยท ์Šน๋ฅ  61.5% ยท PF 1.21 ยท PnL 51,970์› +- ํ‘œ๋ณธ ์žฅ์ด 1์ผ๋ฟ์ด๋ผ, โ€˜์ด์ „ ์žฅ์— ์ž˜ ๋จนํžŒ ์ˆซ์žโ€™์ผ ๋ฟ **์ถ”์„ธ๊ฐ€ ๋ฐ”๋€Œ๋ฉด ๋ฐ”๋กœ ๊นจ์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.** + +## ์•ž์œผ๋กœ ์žฅ์—์„œ๋Š” +- **1~2์ผ Optuna best๋ฅผ ๋ฐ”๋กœ ์‹ค๋งค์— ๋„ฃ์ง€ ๋งˆ์„ธ์š”.** ๋‹ค์ผ(โ‰ฅ5๊ฑฐ๋ž˜์ผ) ์žฌ๊ฒ€์ฆยท์›น๋ฐฑํ…Œ 1ํšŒ ํ›„ ๊ฒ€ํ† . +- ์ ์šฉ ์‹œ์—๋Š” `results_gated` ํ›„๋ณด๋งŒ. ํƒ์ƒ‰์šฉ best(objective)์™€ ๋‹ค๋ฅผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. +- ์žฅ์ด ์ข์•„์ง€๊ฑฐ๋‚˜ ๋ณ€๋™์„ฑ์ด ์ปค์ง€๋ฉด: ์†์ ˆยทํŠธ๋ ˆ์ผยท์‹œ๊ฐ„์ฐฝ์ด ๋จผ์ € ๊นจ์ง‘๋‹ˆ๋‹ค. ์Šน๋ฅ  ์ž๋ž‘๋ณด๋‹ค **์†์ ˆ์ด ์‚ด์•„ ์žˆ๋Š”์ง€**๋ฅผ ๋ณด์„ธ์š”. +- ์‚ฌํ›„ํ•ฉ๊ฒฉ์ด ์žˆ์–ด๋„ โ€˜๋‚ด์ผ๋„ ๊ฐ™์€ ์žฅโ€™์ด ์•„๋‹™๋‹ˆ๋‹ค. ํŽ˜์ดํผ/์†Œ์•กยท๋ชจ์˜๋กœ 1~2์ผ ๊ด€์ฐฐ ํ›„ ํ™•๋Œ€ํ•˜์„ธ์š”. + +_์ƒ์„ฑ: 2026-09-04 20:49:04 (rule)_ + +## AI ์ฝ”๋ฉ˜ํŠธ (์ด์ „ ์žฅ / ์•ž์œผ๋กœ ์žฅ) [gemini] + +## ์ด์ „ ์žฅ์—์„œ๋Š” + +์ง€๋‚œ Optuna TPE๋Š” ๋‹จ ํ•˜๋ฃจ(2026-09-04) ๋ฐ์ดํ„ฐ๋กœ 200๋ฒˆ์˜ ์‹œํ–‰์„ ๊ฑฐ์ณค์Šต๋‹ˆ๋‹ค. ์ด ์ค‘ ์‚ฌํ›„ํ•ฉ๊ฒฉ 1์œ„(#165)๊ฐ€ PnL 51,970์›, ์Šน๋ฅ  61.5%๋กœ ์ข‹์€ ๋ชจ์Šต์„ ๋ณด์˜€์œผ๋‚˜, ์‹ค์ œ ์‹œ์žฅ์—์„œ๋Š” ๋ฐฑํ…Œ์ŠคํŠธ์™€ ๋‹ค๋ฅธ ๊ฒฐ๊ณผ(์‹ค๋งค PnL 12๋งŒ์›, 8๊ฑด ๊ฑฐ๋ž˜)๋ฅผ ๋ณด์˜€์Šต๋‹ˆ๋‹ค. ์ด๋Š” ๋‹จ์ผ ์žฅ์ผ ๋ฐฑํ…Œ์ŠคํŠธ์˜ ๊ณผ์ ํ•ฉ ์œ„ํ—˜์ด ๋งค์šฐ ๋†’๊ณ , ๋ฐฑํ…Œ์ŠคํŠธ์™€ ์‹ค์ œ ์‹œ์žฅ ํ™˜๊ฒฝ(๊ณ ์ŠคํŠธ, ์œ ๋‹ˆ๋ฒ„์Šค, ํ‹ฑ ๊ฒฝ๋กœ ๋“ฑ) ๊ฐ„ ๊ดด๋ฆฌ๊ฐ€ ๋ฐœ์ƒํ–ˆ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. + +## ์•ž์œผ๋กœ ์žฅ์—์„œ๋Š” + +๋‹จ ํ•˜๋ฃจ์น˜ ๊ฒฐ๊ณผ๋Š” ๊ณผ์ ํ•ฉ ์œ„ํ—˜์ด ๋งค์šฐ ๋†’์œผ๋ฏ€๋กœ, ์ฆ‰์‹œ ์‹ค๋งค์— ์ ์šฉํ•ด์„œ๋Š” ์•ˆ ๋ฉ๋‹ˆ๋‹ค. ์•ž์œผ๋กœ๋Š” ์ตœ์†Œ 5์ผ ์ด์ƒ์˜ ๋‹ค์ผ ์žฌ๊ฒ€์ฆ๊ณผ ์›น๋ฐฑํ…Œ์ŠคํŠธ๋ฅผ ํ†ตํ•ด ์•ˆ์ •์„ฑ์„ ๋ฐ˜๋“œ์‹œ ํ™•์ธํ•˜์„ธ์š”. ๋˜ํ•œ, โ€˜mode Top10 1์œ„โ€™๋Š” ์ต์ ˆ ๋Œ€ํ‘œ๊ฐ€ ์•„๋‹ˆ๋ฉฐ, DB 1์ˆœ์œ„์ธ ์‚ฌํ›„ํ•ฉ๊ฒฉ ํ›„๋ณด๋งŒ ์‹ ์ค‘ํžˆ ๊ณ ๋ คํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๋ฐฑํ…Œ์ŠคํŠธ ์ˆ˜์ต์€ ์ ˆ๋Œ€ ์‹ค๋งค ์ˆ˜์ต์„ ๋ณด์žฅํ•˜์ง€ ์•Š์œผ๋ฉฐ, ์‹œ์žฅ ํ™˜๊ฒฝ ๋ณ€ํ™” ์‹œ ํ‘œ๋ณธ ๋ถ€์กฑ์œผ๋กœ ์–ธ์ œ๋“  ์ „๋žต์ด ๊นจ์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์†์ ˆ ๊ธฐ์ค€์ด ์œ ํšจํ•œ์ง€ ํ•ญ์ƒ ์ ๊ฒ€ํ•˜๊ณ , ์ดˆ์†Œ์•ก ๋ชจ์˜ ํˆฌ์ž๋กœ ์ถฉ๋ถ„ํžˆ ๊ด€์ฐฐ ํ›„ ํ™•๋Œ€ ์ ์šฉํ•˜์„ธ์š”. diff --git a/kis_trader/backtest/results/optuna_tail_tpe_20260904_205601.briefing.md b/kis_trader/backtest/results/optuna_tail_tpe_20260904_205601.briefing.md new file mode 100644 index 0000000..0e04b46 --- /dev/null +++ b/kis_trader/backtest/results/optuna_tail_tpe_20260904_205601.briefing.md @@ -0,0 +1,67 @@ +# Optuna ๋ธŒ๋ฆฌํ•‘ โ€” ๊ผฌ๋ฆฌ (tpe) +๊ธฐ๊ฐ„: 2026-09-04 ~ 2026-09-04 (๊ฑฐ๋ž˜์ผโ‰ˆ1์ผ) ยท trials 200/200 +ํƒ์ƒ‰ ๊ฒŒ์ดํŠธ: WRโ‰ฅ0% PFโ‰ฅ0 ยท min_tradesโ‰ฅ1 | ํ›„๋ณด ๊ฒŒ์ดํŠธ: WRโ‰ฅ40% PFโ‰ฅ1 ยท min_tradesโ‰ฅ1 +- min_trades=1: **ํ•ฉ๊ฒฉ ์ธ์ • ์ตœ์†Œ ๊ฑฐ๋ž˜ ๊ฑด์ˆ˜**(ํ‘œ๋ณธ ๋ถ€์กฑยท์šฐ์—ฐ ์Šน๋ฅ  ๋ฐฉ์ง€). ์ด๋ณด๋‹ค ์ ์€ ์กฐํ•ฉ์€ ํ•™์Šต/ํ›„๋ณด ์ง‘๊ณ„์—์„œ ์ œ์™ธ๋ฉ๋‹ˆ๋‹ค. +ํ•™์Šต์šฉ ํ†ต๊ณผ 156๊ฑด ยท ์‚ฌํ›„ํ•ฉ๊ฒฉ(results_gated) 43๊ฑด + +## ๊ณผ์ ํ•ฉยท์ ์šฉ ๊ฐ€๋Šฅ๋„ (ํœด๋ฆฌ์Šคํ‹ฑ) +- **๊ณผ์ ํ•ฉ ์œ„ํ—˜ 40.0%** ยท **์ ์šฉ ๊ฐ€๋Šฅ๋„ 60.0%** ยท ํŒ์ •: **์ฃผ์˜** โ€” ์ ์šฉ ๊ฐ€๋Šฅ๋„ ์ค‘๊ฐ„ โ€” ๋‹ค์ผ(โ‰ฅ5์ผ) ์žฌ๊ฒ€์ฆยท์›น๋ฐฑํ…Œ ํ›„ ์†Œ์•ก๋งŒ + - ํ‘œ๋ณธ ์žฅ์ผ: +40.0p โ€” ๊ฑฐ๋ž˜์ผโ‰ˆ1์ผ โ€” ๋‹จ์ผ ์žฅ ๊ณผ์ ํ•ฉ ์œ„ํ—˜ ์ตœ๋Œ€ + - ๊ฑฐ๋ž˜ ํ‘œ๋ณธ: +0.0p โ€” ์ƒ์œ„ ํ›„๋ณด ๊ฑฐ๋ž˜ 111๊ฑด โ€” ์ƒ๋Œ€์  ์–‘ํ˜ธ + - ์Šน๋ฅ ยทPF ์ด์ƒ์น˜: +0.0p โ€” ์ด์ƒ์น˜ ์—†์Œ + - ๊ฒŒ์ดํŠธ ์ปค๋ฒ„: +0.0p โ€” ์‚ฌํ›„ํ•ฉ๊ฒฉ 43๊ฑด ยท stable 10๊ฑด + - PnL ๊ณ ์›: +0.0p โ€” ๊ณ ์› ๋น„์œจ 2% (1๊ฑด) +- ์ž„๊ณ„๊ฐ’ ๋ถ„ํฌ ํ‘œ๋ณธ: results_gated ์ƒ์œ„ 30๊ฑด +| ํŒŒ๋ผ๋ฏธํ„ฐ | median | p25~p75 | mode(๋น„์œจ) | +|---|---:|---|---| +| `entry_mode` | โ€” | โ€” | align (100%) | +| `cand_limit` | 0.0 | 0.0 ~ 0.0 | 0 (83%) | +| `max_daily_change` | 35.5 | 30.25 ~ 43.75 | 34.0 (10%) | +| `min_drop_rate` | 0.015 | 0.01 ~ 0.025 | 0.015 (20%) | +| `min_recovery_ratio` | 0.165 | 0.1325 ~ 0.2 | 0.11 (13%) | +| `tail_ratio_min` | 1.0 | 0.825 ~ 1.2 | 1.0 (20%) | +| `tail_pct_min` | 0.00575 | 0.004 ~ 0.007375 | 0.004 (10%) | +| `max_rec_3m` | 0.77 | 0.73 ~ 0.8375 | 0.73 (13%) | +| `shoulder_min_high` | 0.003 | 0.002 ~ 0.004 | 0.002 (30%) | +| `shoulder_cut_pct` | 0.001 | 0.0005 ~ 0.002 | 0.0005 (33%) | +| `stop_atr_mult` | 2.45 | 2.3 ~ 2.6 | 2.3 (17%) | +| `target_atr_mult` | 1.4 | 1.025 ~ 1.7 | 1.9 (13%) | +- _์ฐธ๊ณ : ๊ณผ์ ํ•ฉ%๋Š” ๊ต์ฐจ๊ฒ€์ฆ ์ ์ˆ˜๊ฐ€ ์•„๋‹ˆ๋ผ ํ‘œ๋ณธยท์ด์ƒ์น˜ยท๊ณ ์› ํœด๋ฆฌ์Šคํ‹ฑ์ž…๋‹ˆ๋‹ค. ์ ์šฉ ๊ฐ€๋Šฅ๋„%=100โˆ’๊ณผ์ ํ•ฉ์œ„ํ—˜%. DB ์ ์šฉ ๋ฒ„ํŠผ ํ™œ์„ฑ ์กฐ๊ฑด(gated PnL>0)๊ณผ๋Š” ๋ณ„๊ฐœ์ž…๋‹ˆ๋‹ค._ + +## ์ตœ์ข… ์„ ํƒ ํ›„๋ณด (๊ทœ์น™ ยท DB ์ ์šฉ ์ „ ํ™•์ธ) +- ์•„๋ž˜๋Š” **์—ญํ• ์ด ๋‹ค๋ฅธ** 4์ข… ํ›„๋ณด์ž…๋‹ˆ๋‹ค. mode Top10 1์œ„ โ‰  ์ต์ ˆ ๋Œ€ํ‘œ ยท **DB 1์ˆœ์œ„๋Š” ์‚ฌํ›„ํ•ฉ๊ฒฉ(gated)** ์ž…๋‹ˆ๋‹ค. +- mode pool: `positive` ยท scoring: `band_proximity_p25_p75` + +### ํ›„๋ณด 4์ข… +- **โ‘  ์‚ฌํ›„ํ•ฉ๊ฒฉ 1์œ„ (apply: gated)** (trial #137): PnL 51,346์› ยท WR 58.6% ยท PF 1.41 ยท ๊ฑฐ๋ž˜ 111๊ฑด ยท ์•ˆ์ •์ ์ˆ˜ -1963 ยท ํ˜ธ๊ฐ€ON spr0.5 r1.05 askร—20 ยท ํœฉ์˜OFF +- **โ‘ก ์•ˆ์ • 1์œ„ (apply: stable)** (trial #189): PnL 41,761์› ยท WR 57.1% ยท PF 1.73 ยท ๊ฑฐ๋ž˜ 63๊ฑด ยท ์•ˆ์ •์ ์ˆ˜ 3503 ยท ํ˜ธ๊ฐ€ON spr0.8 r1.40 askร—20 ยท ํœฉ์˜OFF +- **โ‘ข mode_combo (apply: mode)** (trial ์—†์Œ(์กฐ๋ฆฝ)): PnL 87์› ยท WR 77.6% ยท PF 1.01 ยท ๊ฑฐ๋ž˜ 174๊ฑด ยท ์•ˆ์ •์ ์ˆ˜ -879 ยท ํ˜ธ๊ฐ€ON spr1.2 r1.05 askร—54 ยท ํœฉ์˜OFF +- **โ‘ฃ mode Top10 1์œ„ (apply: consensus ยท ๋ฐด๋“œ ์ „ํ˜• trial)** (trial #103): PnL 10,251์› ยท WR 71.0% ยท PF 1.08 ยท ๊ฑฐ๋ž˜ 62๊ฑด ยท ์•ˆ์ •์ ์ˆ˜ -11076 ยท ๊ทผ์ ‘ 96.6% (44/52์ถ• ๋ฐด๋“œ์•ˆ) ยท ํ˜ธ๊ฐ€ON spr3.2 r1.20 askร—59 ยท ํœฉ์˜OFF +- mode Top10 meta: pool 43๊ฑด ยท ์ถ• 52๊ฐœ + +### ์ถ”์ฒœ (์ž๋™ ยท confirm ํ•„์ˆ˜) +1. **์‹ค๋งค DB ์ ์šฉ 1์ˆœ์œ„ โ†’ โ‘  ์‚ฌํ›„ํ•ฉ๊ฒฉ 1์œ„** (`optunaApply gated`) โ€” WR/PFยทmin_trades ์‚ฌํ›„ ํ†ต๊ณผ. +2. **๋ณ€๋™์„ฑยท์†์‹ค์ผ ์ค„์ด๊ธฐ โ†’ โ‘ก ์•ˆ์ • 1์œ„** (`stable`) โ€” PnL๋ณด๋‹ค ์ผ๋ณ„ ์•ˆ์ • ์šฐ์„  ์‹œ. +3. **2์ฐจ narrowยท๋Œ€ํ‘œ ์ˆซ์ž โ†’ โ‘ข mode_combo** โ€” ์ถ•๋ณ„ ์ตœ๋นˆ ์กฐ๋ฆฝ ยท trial ๋ฒˆํ˜ธ ์—†์Œ ยท ์ต์ ˆ์€ pool ์ตœ๋นˆ๊ฐ’ ์ฐธ๊ณ . +4. **โ‘ฃ mode Top10 1์œ„** โ€” ์–‘์ˆ˜ pool ์ „ํ˜• trial(๋‹ค์ถ• ๋ฐด๋“œ ๊ทผ์ ‘). **์ต์ ˆ ํ•˜๋‚˜๋กœ ์“ฐ์ง€ ๋ง ๊ฒƒ** ยท ํ‘œ์—์„œ ใ€Œ๋ณด๊ธฐใ€โ†’ consensus apply. + +## ์ด์ „ ์žฅ์—์„œ๋Š” +- ์‹ค๋งค ๋™๊ธฐ๊ฐ„ ์ฒญ์‚ฐ 8๊ฑด ยท ์Šน๋ฅ  50% ยท ํ•ฉ์‚ฐ PnL 121,682์› (๋ฐฑํ…Œ Optuna์™€ ์ˆซ์ž ๋‹ฌ๋ผ๋„ ์ •์ƒ โ€” ๊ณ ์ŠคํŠธยท์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑ ๊ฒฝ๋กœ ์ฐจ์ด). +- ์‚ฌํ›„ํ•ฉ๊ฒฉ 1์œ„: trial #137 ยท ๊ฑฐ๋ž˜ 111๊ฑด ยท ์Šน๋ฅ  58.6% ยท PF 1.41 ยท PnL 51,346์› +- ํ‘œ๋ณธ ์žฅ์ด 1์ผ๋ฟ์ด๋ผ, โ€˜์ด์ „ ์žฅ์— ์ž˜ ๋จนํžŒ ์ˆซ์žโ€™์ผ ๋ฟ **์ถ”์„ธ๊ฐ€ ๋ฐ”๋€Œ๋ฉด ๋ฐ”๋กœ ๊นจ์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.** + +## ์•ž์œผ๋กœ ์žฅ์—์„œ๋Š” +- **1~2์ผ Optuna best๋ฅผ ๋ฐ”๋กœ ์‹ค๋งค์— ๋„ฃ์ง€ ๋งˆ์„ธ์š”.** ๋‹ค์ผ(โ‰ฅ5๊ฑฐ๋ž˜์ผ) ์žฌ๊ฒ€์ฆยท์›น๋ฐฑํ…Œ 1ํšŒ ํ›„ ๊ฒ€ํ† . +- ์ ์šฉ ์‹œ์—๋Š” `results_gated` ํ›„๋ณด๋งŒ. ํƒ์ƒ‰์šฉ best(objective)์™€ ๋‹ค๋ฅผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. +- ์žฅ์ด ์ข์•„์ง€๊ฑฐ๋‚˜ ๋ณ€๋™์„ฑ์ด ์ปค์ง€๋ฉด: ์†์ ˆยทํŠธ๋ ˆ์ผยท์‹œ๊ฐ„์ฐฝ์ด ๋จผ์ € ๊นจ์ง‘๋‹ˆ๋‹ค. ์Šน๋ฅ  ์ž๋ž‘๋ณด๋‹ค **์†์ ˆ์ด ์‚ด์•„ ์žˆ๋Š”์ง€**๋ฅผ ๋ณด์„ธ์š”. +- ์‚ฌํ›„ํ•ฉ๊ฒฉ์ด ์žˆ์–ด๋„ โ€˜๋‚ด์ผ๋„ ๊ฐ™์€ ์žฅโ€™์ด ์•„๋‹™๋‹ˆ๋‹ค. ํŽ˜์ดํผ/์†Œ์•กยท๋ชจ์˜๋กœ 1~2์ผ ๊ด€์ฐฐ ํ›„ ํ™•๋Œ€ํ•˜์„ธ์š”. + +_์ƒ์„ฑ: 2026-09-04 20:56:03 (rule)_ + +## AI ์ฝ”๋ฉ˜ํŠธ (์ด์ „ ์žฅ / ์•ž์œผ๋กœ ์žฅ) [gemini] + +**์ด์ „ ์žฅ์—์„œ๋Š”** +๋‹จ์ผ ๊ฑฐ๋ž˜์ผ(2026-09-04) ๋ฐฑํ…Œ์ŠคํŠธ ๊ฒฐ๊ณผ์ž…๋‹ˆ๋‹ค. ์‹ค๋งค์—์„œ๋Š” 8๊ฑด ์ฒญ์‚ฐ, ์Šน๋ฅ  50%, PnL 121,682์›์ด์—ˆ์Šต๋‹ˆ๋‹ค. ๋ฐฑํ…Œ์ŠคํŠธ์™€ ์‹ค๋งค ๊ฐ„ PnL ๊ดด๋ฆฌ๋Š” ๊ณ ์ŠคํŠธํผ์ง€ ๋“ฑ ๋‹ค์–‘ํ•œ ์š”์ธ์œผ๋กœ ์ •์ƒ์ด๋ฉฐ, Optuna ์‚ฌํ›„ํ•ฉ๊ฒฉ 1์œ„(#137)๋Š” PnL 51,346์›, ์Šน๋ฅ  58.6%, PF 1.41์ž…๋‹ˆ๋‹ค. ๋‹จ์ผ ์žฅ์ผ ๋ฐ์ดํ„ฐ๋Š” ๊ณผ์ ํ•ฉ ์œ„ํ—˜์ด ๋งค์šฐ ๋†’์œผ๋ฉฐ, ์‹œ์žฅ ์ถ”์„ธ ๋ณ€ํ™” ์‹œ ์ „๋žต์€ ์ฆ‰์‹œ ๋ฌดํšจํ™”๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. + +**์•ž์œผ๋กœ ์žฅ์—์„œ๋Š”** +๋‹จ 1์ผ์น˜ Optuna ๊ฒฐ๊ณผ๋Š” ๊ณผ์ ํ•ฉ ์œ„ํ—˜์ด ์ปค ์‹ค๋งค ์ ์šฉ์„ ๊ฐ•๋ ฅํžˆ ๊ฒฝ๊ณ ํ•ฉ๋‹ˆ๋‹ค. ์ตœ์†Œ 5์ผ ์ด์ƒ ์žฌ๊ฒ€์ฆ๊ณผ ์›น๋ฐฑํ…Œ์ŠคํŠธ ํ›„ ์†Œ์•ก์œผ๋กœ ์‹œ์ž‘ํ•˜์„ธ์š”. `mode Top10 1์œ„`๋Š” ์ต์ ˆ ๋Œ€ํ‘œ๊ฐ€ ์•„๋‹ˆ๋ฉฐ, DB 1์ˆœ์œ„๋Š” ์‚ฌํ›„ํ•ฉ๊ฒฉ(gated) ํ›„๋ณด์ž…๋‹ˆ๋‹ค. ์‹ค๋งค์™€ ๋ฐฑํ…Œ์ŠคํŠธ ๊ฐ„ ๊ดด๋ฆฌ(๊ณ ์ŠคํŠธํผ์ง€, ํ‘œ๋ณธ ๋ถ€์กฑ ๋“ฑ)๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์œผ๋‹ˆ ๋ชจ์˜/์†Œ์•ก ๊ด€์ฐฐ์ด ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค. ํŠน์ • ์ข…๋ชฉ ๋งค์ˆ˜ ์ถ”์ฒœ์ด๋‚˜ ํ™•์ • ์ˆ˜์ต์€ ๊ธˆ์ง€๋˜๋ฉฐ, ๋†’์€ ์Šน๋ฅ ๋ณด๋‹ค ์†์ ˆ ๊ธฐ๋Šฅ ์œ ์ง€๊ฐ€ ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค. diff --git a/kis_trader/backtest/results/optuna_tail_tpe_20260904_210041.briefing.md b/kis_trader/backtest/results/optuna_tail_tpe_20260904_210041.briefing.md new file mode 100644 index 0000000..3cc0c03 --- /dev/null +++ b/kis_trader/backtest/results/optuna_tail_tpe_20260904_210041.briefing.md @@ -0,0 +1,69 @@ +# Optuna ๋ธŒ๋ฆฌํ•‘ โ€” ๊ผฌ๋ฆฌ (tpe) +๊ธฐ๊ฐ„: 2026-09-04 ~ 2026-09-04 (๊ฑฐ๋ž˜์ผโ‰ˆ1์ผ) ยท trials 200/200 +ํƒ์ƒ‰ ๊ฒŒ์ดํŠธ: WRโ‰ฅ0% PFโ‰ฅ0 ยท min_tradesโ‰ฅ1 | ํ›„๋ณด ๊ฒŒ์ดํŠธ: WRโ‰ฅ40% PFโ‰ฅ1 ยท min_tradesโ‰ฅ1 +- min_trades=1: **ํ•ฉ๊ฒฉ ์ธ์ • ์ตœ์†Œ ๊ฑฐ๋ž˜ ๊ฑด์ˆ˜**(ํ‘œ๋ณธ ๋ถ€์กฑยท์šฐ์—ฐ ์Šน๋ฅ  ๋ฐฉ์ง€). ์ด๋ณด๋‹ค ์ ์€ ์กฐํ•ฉ์€ ํ•™์Šต/ํ›„๋ณด ์ง‘๊ณ„์—์„œ ์ œ์™ธ๋ฉ๋‹ˆ๋‹ค. +ํ•™์Šต์šฉ ํ†ต๊ณผ 164๊ฑด ยท ์‚ฌํ›„ํ•ฉ๊ฒฉ(results_gated) 73๊ฑด + +## ๊ณผ์ ํ•ฉยท์ ์šฉ ๊ฐ€๋Šฅ๋„ (ํœด๋ฆฌ์Šคํ‹ฑ) +- **๊ณผ์ ํ•ฉ ์œ„ํ—˜ 40.0%** ยท **์ ์šฉ ๊ฐ€๋Šฅ๋„ 60.0%** ยท ํŒ์ •: **์ฃผ์˜** โ€” ์ ์šฉ ๊ฐ€๋Šฅ๋„ ์ค‘๊ฐ„ โ€” ๋‹ค์ผ(โ‰ฅ5์ผ) ์žฌ๊ฒ€์ฆยท์›น๋ฐฑํ…Œ ํ›„ ์†Œ์•ก๋งŒ + - ํ‘œ๋ณธ ์žฅ์ผ: +40.0p โ€” ๊ฑฐ๋ž˜์ผโ‰ˆ1์ผ โ€” ๋‹จ์ผ ์žฅ ๊ณผ์ ํ•ฉ ์œ„ํ—˜ ์ตœ๋Œ€ + - ๊ฑฐ๋ž˜ ํ‘œ๋ณธ: +0.0p โ€” ์ƒ์œ„ ํ›„๋ณด ๊ฑฐ๋ž˜ 180๊ฑด โ€” ์ƒ๋Œ€์  ์–‘ํ˜ธ + - ์Šน๋ฅ ยทPF ์ด์ƒ์น˜: +0.0p โ€” ์ด์ƒ์น˜ ์—†์Œ + - ๊ฒŒ์ดํŠธ ์ปค๋ฒ„: +0.0p โ€” ์‚ฌํ›„ํ•ฉ๊ฒฉ 73๊ฑด ยท stable 10๊ฑด + - PnL ๊ณ ์›: +0.0p โ€” ๊ณ ์› ๋น„์œจ 1% (1๊ฑด) +- ์ž„๊ณ„๊ฐ’ ๋ถ„ํฌ ํ‘œ๋ณธ: results_gated ์ƒ์œ„ 30๊ฑด +| ํŒŒ๋ผ๋ฏธํ„ฐ | median | p25~p75 | mode(๋น„์œจ) | +|---|---:|---|---| +| `entry_mode` | โ€” | โ€” | align (100%) | +| `cand_limit` | 20.0 | 0.0 ~ 20.0 | 20 (60%) | +| `max_daily_change` | 46.0 | 39.5 ~ 51.5 | 41.0 (10%) | +| `min_drop_rate` | 0.015 | 0.005 ~ 0.02 | 0.005 (30%) | +| `min_recovery_ratio` | 0.15 | 0.1225 ~ 0.17 | 0.17 (20%) | +| `tail_ratio_min` | 1.05 | 0.825 ~ 1.2 | 1.1 (20%) | +| `tail_pct_min` | 0.00525 | 0.003125 ~ 0.006875 | 0.006 (13%) | +| `max_rec_3m` | 0.75 | 0.715 ~ 0.84 | 0.71 (17%) | +| `shoulder_min_high` | 0.003 | 0.002 ~ 0.00475 | 0.002 (37%) | +| `shoulder_cut_pct` | 0.001 | 0.0005 ~ 0.0015 | 0.0005 (33%) | +| `stop_atr_mult` | 1.5 | 1.4 ~ 1.975 | 1.4 (17%) | +| `target_atr_mult` | 2.4 | 1.725 ~ 2.875 | 2.4 (10%) | +- _์ฐธ๊ณ : ๊ณผ์ ํ•ฉ%๋Š” ๊ต์ฐจ๊ฒ€์ฆ ์ ์ˆ˜๊ฐ€ ์•„๋‹ˆ๋ผ ํ‘œ๋ณธยท์ด์ƒ์น˜ยท๊ณ ์› ํœด๋ฆฌ์Šคํ‹ฑ์ž…๋‹ˆ๋‹ค. ์ ์šฉ ๊ฐ€๋Šฅ๋„%=100โˆ’๊ณผ์ ํ•ฉ์œ„ํ—˜%. DB ์ ์šฉ ๋ฒ„ํŠผ ํ™œ์„ฑ ์กฐ๊ฑด(gated PnL>0)๊ณผ๋Š” ๋ณ„๊ฐœ์ž…๋‹ˆ๋‹ค._ + +## ์ตœ์ข… ์„ ํƒ ํ›„๋ณด (๊ทœ์น™ ยท DB ์ ์šฉ ์ „ ํ™•์ธ) +- ์•„๋ž˜๋Š” **์—ญํ• ์ด ๋‹ค๋ฅธ** 4์ข… ํ›„๋ณด์ž…๋‹ˆ๋‹ค. mode Top10 1์œ„ โ‰  ์ต์ ˆ ๋Œ€ํ‘œ ยท **DB 1์ˆœ์œ„๋Š” ์‚ฌํ›„ํ•ฉ๊ฒฉ(gated)** ์ž…๋‹ˆ๋‹ค. +- mode pool: `positive` ยท scoring: `band_proximity_p25_p75` + +### ํ›„๋ณด 4์ข… +- **โ‘  ์‚ฌํ›„ํ•ฉ๊ฒฉ 1์œ„ (apply: gated)** (trial #172): PnL 118,141์› ยท WR 75.6% ยท PF 1.71 ยท ๊ฑฐ๋ž˜ 180๊ฑด ยท ์•ˆ์ •์ ์ˆ˜ -25169 ยท ํ˜ธ๊ฐ€ON spr4.6 r0.25 askร—3 ยท ํœฉ์˜ON sub45s lb60s dip0.30% tol0.25% +- **โ‘ก ์•ˆ์ • 1์œ„ (apply: stable)** (trial #188): PnL 27,201์› ยท WR 68.4% ยท PF 1.63 ยท ๊ฑฐ๋ž˜ 19๊ฑด ยท ์•ˆ์ •์ ์ˆ˜ 6617 ยท ํ˜ธ๊ฐ€ON spr6.3 r0.25 askร—18 ยท ํœฉ์˜ON sub45s lb60s dip0.20% tol0.20% +- **โ‘ข mode_combo (apply: mode)** (trial ์—†์Œ(์กฐ๋ฆฝ)): PnL -8,882์› ยท WR 66.2% ยท PF 0.78 ยท ๊ฑฐ๋ž˜ 302๊ฑด ยท ์•ˆ์ •์ ์ˆ˜ -4874 ยท ํ˜ธ๊ฐ€OFF ยท ํœฉ์˜OFF +- **โ‘ฃ mode Top10 1์œ„ (apply: consensus ยท ๋ฐด๋“œ ์ „ํ˜• trial)** (trial #134): PnL 23,278์› ยท WR 71.0% ยท PF 1.44 ยท ๊ฑฐ๋ž˜ 31๊ฑด ยท ์•ˆ์ •์ ์ˆ˜ -3812 ยท ๊ทผ์ ‘ 98.2% (45/52์ถ• ๋ฐด๋“œ์•ˆ) ยท ํ˜ธ๊ฐ€OFF ยท ํœฉ์˜OFF +- mode Top10 meta: pool 74๊ฑด ยท ์ถ• 52๊ฐœ + +### ์ถ”์ฒœ (์ž๋™ ยท confirm ํ•„์ˆ˜) +1. **์‹ค๋งค DB ์ ์šฉ 1์ˆœ์œ„ โ†’ โ‘  ์‚ฌํ›„ํ•ฉ๊ฒฉ 1์œ„** (`optunaApply gated`) โ€” WR/PFยทmin_trades ์‚ฌํ›„ ํ†ต๊ณผ. +2. **๋ณ€๋™์„ฑยท์†์‹ค์ผ ์ค„์ด๊ธฐ โ†’ โ‘ก ์•ˆ์ • 1์œ„** (`stable`) โ€” PnL๋ณด๋‹ค ์ผ๋ณ„ ์•ˆ์ • ์šฐ์„  ์‹œ. +3. **2์ฐจ narrowยท๋Œ€ํ‘œ ์ˆซ์ž โ†’ โ‘ข mode_combo** โ€” ์ถ•๋ณ„ ์ตœ๋นˆ ์กฐ๋ฆฝ ยท trial ๋ฒˆํ˜ธ ์—†์Œ ยท ์ต์ ˆ์€ pool ์ตœ๋นˆ๊ฐ’ ์ฐธ๊ณ . +4. **โ‘ฃ mode Top10 1์œ„** โ€” ์–‘์ˆ˜ pool ์ „ํ˜• trial(๋‹ค์ถ• ๋ฐด๋“œ ๊ทผ์ ‘). **์ต์ ˆ ํ•˜๋‚˜๋กœ ์“ฐ์ง€ ๋ง ๊ฒƒ** ยท ํ‘œ์—์„œ ใ€Œ๋ณด๊ธฐใ€โ†’ consensus apply. + +## ์ด์ „ ์žฅ์—์„œ๋Š” +- ์‹ค๋งค ๋™๊ธฐ๊ฐ„ ์ฒญ์‚ฐ 8๊ฑด ยท ์Šน๋ฅ  50% ยท ํ•ฉ์‚ฐ PnL 121,682์› (๋ฐฑํ…Œ Optuna์™€ ์ˆซ์ž ๋‹ฌ๋ผ๋„ ์ •์ƒ โ€” ๊ณ ์ŠคํŠธยท์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑ ๊ฒฝ๋กœ ์ฐจ์ด). +- ์‚ฌํ›„ํ•ฉ๊ฒฉ 1์œ„: trial #172 ยท ๊ฑฐ๋ž˜ 180๊ฑด ยท ์Šน๋ฅ  75.6% ยท PF 1.71 ยท PnL 118,141์› +- ํ‘œ๋ณธ ์žฅ์ด 1์ผ๋ฟ์ด๋ผ, โ€˜์ด์ „ ์žฅ์— ์ž˜ ๋จนํžŒ ์ˆซ์žโ€™์ผ ๋ฟ **์ถ”์„ธ๊ฐ€ ๋ฐ”๋€Œ๋ฉด ๋ฐ”๋กœ ๊นจ์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.** + +## ์•ž์œผ๋กœ ์žฅ์—์„œ๋Š” +- **1~2์ผ Optuna best๋ฅผ ๋ฐ”๋กœ ์‹ค๋งค์— ๋„ฃ์ง€ ๋งˆ์„ธ์š”.** ๋‹ค์ผ(โ‰ฅ5๊ฑฐ๋ž˜์ผ) ์žฌ๊ฒ€์ฆยท์›น๋ฐฑํ…Œ 1ํšŒ ํ›„ ๊ฒ€ํ† . +- ์ ์šฉ ์‹œ์—๋Š” `results_gated` ํ›„๋ณด๋งŒ. ํƒ์ƒ‰์šฉ best(objective)์™€ ๋‹ค๋ฅผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. +- ์žฅ์ด ์ข์•„์ง€๊ฑฐ๋‚˜ ๋ณ€๋™์„ฑ์ด ์ปค์ง€๋ฉด: ์†์ ˆยทํŠธ๋ ˆ์ผยท์‹œ๊ฐ„์ฐฝ์ด ๋จผ์ € ๊นจ์ง‘๋‹ˆ๋‹ค. ์Šน๋ฅ  ์ž๋ž‘๋ณด๋‹ค **์†์ ˆ์ด ์‚ด์•„ ์žˆ๋Š”์ง€**๋ฅผ ๋ณด์„ธ์š”. +- ์‚ฌํ›„ํ•ฉ๊ฒฉ์ด ์žˆ์–ด๋„ โ€˜๋‚ด์ผ๋„ ๊ฐ™์€ ์žฅโ€™์ด ์•„๋‹™๋‹ˆ๋‹ค. ํŽ˜์ดํผ/์†Œ์•กยท๋ชจ์˜๋กœ 1~2์ผ ๊ด€์ฐฐ ํ›„ ํ™•๋Œ€ํ•˜์„ธ์š”. + +_์ƒ์„ฑ: 2026-09-04 21:00:43 (rule)_ + +## AI ์ฝ”๋ฉ˜ํŠธ (์ด์ „ ์žฅ / ์•ž์œผ๋กœ ์žฅ) [gemini] + +## ์ด์ „ ์žฅ์—์„œ๋Š” + +์ง€๋‚œ 1์ผ ๋ฐฑํ…Œ์ŠคํŠธ์—์„œ ์‚ฌํ›„ํ•ฉ๊ฒฉ 1์œ„(#172)๊ฐ€ PnL 11.8๋งŒ์›์˜ ์ข‹์€ ๊ฒฐ๊ณผ๋ฅผ ๋ณด์˜€์Šต๋‹ˆ๋‹ค. ์‹ค๋งค ๋˜ํ•œ PnL 12.1๋งŒ์›์„ ๊ธฐ๋กํ–ˆ์œผ๋‚˜, ๋ฐฑํ…Œ์ŠคํŠธ์™€ ์‹ค๋งค ๊ฐ„์—๋Š” ๊ณ ์ŠคํŠธ ํŠธ๋ ˆ์ด๋“œ ๋“ฑ์œผ๋กœ ๊ดด๋ฆฌ๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. ๋‹จ 1์ผ ํ‘œ๋ณธ์€ ๊ณผ์ ํ•ฉ ์œ„ํ—˜์ด ๊ทน๋Œ€ํ™”๋˜๋ฏ€๋กœ, ์ด ๊ฒฐ๊ณผ๋Š” ๊ณผ๊ฑฐ ์‹œ์žฅ์˜ ์šฐ์—ฐ์ผ ๋ฟ ๋ฏธ๋ž˜ ์ˆ˜์ต์„ ๋ณด์žฅํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. + +## ์•ž์œผ๋กœ ์žฅ์—์„œ๋Š” + +์•ž์œผ๋กœ 1์ผ ์ตœ์ ํ™” ์ „๋žต์„ ๋ฐ”๋กœ ์‹ค๋งค์— ์ ์šฉ ๋งˆ์„ธ์š”. ์ตœ์†Œ 5์ผ ์ด์ƒ ๋‹ค์ผ ์žฌ๊ฒ€์ฆ๊ณผ ์›น๋ฐฑํ…Œ์ŠคํŠธ ํ›„ ์†Œ์•ก์œผ๋กœ ์‹œ์ž‘ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์‹œ์žฅ์€ ๋งค์ผ ๋ณ€ํ•˜๋ฉฐ ๊ณผ์ ํ•ฉ ์œ„ํ—˜์ด ๋†’์œผ๋‹ˆ, ์Šน๋ฅ ๋ณด๋‹ค '์†์ ˆ ๊ธฐ๋Šฅ' ์ž‘๋™ ์—ฌ๋ถ€ ํ™•์ธ์ด ํ•ต์‹ฌ์ž…๋‹ˆ๋‹ค. โ‘ฃ๋ฒˆ mode Top10 1์œ„๋Š” ์ต์ ˆ ๋Œ€ํ‘œ๊ฐ€ ์•„๋‹ˆ๋ฉฐ, ํ™•์ • ์ˆ˜์ต์€ ์•ฝ์† ๋ถˆ๊ฐ€ํ•ฉ๋‹ˆ๋‹ค. ์‹ค๋งค ์ „ ๋ชจ์˜/ํŽ˜์ดํผ ๊ฑฐ๋ž˜๋กœ ์ถฉ๋ถ„ํžˆ ๊ด€์ฐฐ ๋ฐ”๋ž๋‹ˆ๋‹ค. diff --git a/kis_trader/backtest/results/optuna_tail_tpe_20260905_001457.briefing.md b/kis_trader/backtest/results/optuna_tail_tpe_20260905_001457.briefing.md new file mode 100644 index 0000000..5ac072e --- /dev/null +++ b/kis_trader/backtest/results/optuna_tail_tpe_20260905_001457.briefing.md @@ -0,0 +1,69 @@ +# Optuna ๋ธŒ๋ฆฌํ•‘ โ€” ๊ผฌ๋ฆฌ (tpe) +๊ธฐ๊ฐ„: 2026-09-04 ~ 2026-09-04 (๊ฑฐ๋ž˜์ผโ‰ˆ1์ผ) ยท trials 200/200 +ํƒ์ƒ‰ ๊ฒŒ์ดํŠธ: WRโ‰ฅ0% PFโ‰ฅ0 ยท min_tradesโ‰ฅ1 | ํ›„๋ณด ๊ฒŒ์ดํŠธ: WRโ‰ฅ40% PFโ‰ฅ1 ยท min_tradesโ‰ฅ1 +- min_trades=1: **ํ•ฉ๊ฒฉ ์ธ์ • ์ตœ์†Œ ๊ฑฐ๋ž˜ ๊ฑด์ˆ˜**(ํ‘œ๋ณธ ๋ถ€์กฑยท์šฐ์—ฐ ์Šน๋ฅ  ๋ฐฉ์ง€). ์ด๋ณด๋‹ค ์ ์€ ์กฐํ•ฉ์€ ํ•™์Šต/ํ›„๋ณด ์ง‘๊ณ„์—์„œ ์ œ์™ธ๋ฉ๋‹ˆ๋‹ค. +ํ•™์Šต์šฉ ํ†ต๊ณผ 176๊ฑด ยท ์‚ฌํ›„ํ•ฉ๊ฒฉ(results_gated) 125๊ฑด + +## ๊ณผ์ ํ•ฉยท์ ์šฉ ๊ฐ€๋Šฅ๋„ (ํœด๋ฆฌ์Šคํ‹ฑ) +- **๊ณผ์ ํ•ฉ ์œ„ํ—˜ 40.0%** ยท **์ ์šฉ ๊ฐ€๋Šฅ๋„ 60.0%** ยท ํŒ์ •: **์ฃผ์˜** โ€” ์ ์šฉ ๊ฐ€๋Šฅ๋„ ์ค‘๊ฐ„ โ€” ๋‹ค์ผ(โ‰ฅ5์ผ) ์žฌ๊ฒ€์ฆยท์›น๋ฐฑํ…Œ ํ›„ ์†Œ์•ก๋งŒ + - ํ‘œ๋ณธ ์žฅ์ผ: +40.0p โ€” ๊ฑฐ๋ž˜์ผโ‰ˆ1์ผ โ€” ๋‹จ์ผ ์žฅ ๊ณผ์ ํ•ฉ ์œ„ํ—˜ ์ตœ๋Œ€ + - ๊ฑฐ๋ž˜ ํ‘œ๋ณธ: +0.0p โ€” ์ƒ์œ„ ํ›„๋ณด ๊ฑฐ๋ž˜ 98๊ฑด โ€” ์ƒ๋Œ€์  ์–‘ํ˜ธ + - ์Šน๋ฅ ยทPF ์ด์ƒ์น˜: +0.0p โ€” ์ด์ƒ์น˜ ์—†์Œ + - ๊ฒŒ์ดํŠธ ์ปค๋ฒ„: +0.0p โ€” ์‚ฌํ›„ํ•ฉ๊ฒฉ 125๊ฑด ยท stable 10๊ฑด + - PnL ๊ณ ์›: +0.0p โ€” ๊ณ ์› ๋น„์œจ 1% (1๊ฑด) +- ์ž„๊ณ„๊ฐ’ ๋ถ„ํฌ ํ‘œ๋ณธ: results_gated ์ƒ์œ„ 30๊ฑด +| ํŒŒ๋ผ๋ฏธํ„ฐ | median | p25~p75 | mode(๋น„์œจ) | +|---|---:|---|---| +| `entry_mode` | โ€” | โ€” | align (100%) | +| `cand_limit` | 0.0 | 0.0 ~ 0.0 | 0 (97%) | +| `max_daily_change` | 30.5 | 20.25 ~ 46.0 | 27.0 (10%) | +| `min_drop_rate` | 0.01 | 0.005 ~ 0.01 | 0.01 (50%) | +| `min_recovery_ratio` | 0.12 | 0.1 ~ 0.14 | 0.14 (20%) | +| `tail_ratio_min` | 0.5 | 0.4 ~ 0.6 | 0.4 (40%) | +| `tail_pct_min` | 0.0075 | 0.007 ~ 0.009 | 0.0075 (23%) | +| `max_rec_3m` | 0.86 | 0.8275 ~ 0.8975 | 0.88 (13%) | +| `shoulder_min_high` | 0.003 | 0.002 ~ 0.004 | 0.002 (43%) | +| `shoulder_cut_pct` | 0.001 | 0.0005 ~ 0.001375 | 0.001 (40%) | +| `stop_atr_mult` | 1.5 | 1.2 ~ 1.7 | 1.7 (13%) | +| `target_atr_mult` | 2.15 | 1.625 ~ 3.1 | 3.1 (10%) | +- _์ฐธ๊ณ : ๊ณผ์ ํ•ฉ%๋Š” ๊ต์ฐจ๊ฒ€์ฆ ์ ์ˆ˜๊ฐ€ ์•„๋‹ˆ๋ผ ํ‘œ๋ณธยท์ด์ƒ์น˜ยท๊ณ ์› ํœด๋ฆฌ์Šคํ‹ฑ์ž…๋‹ˆ๋‹ค. ์ ์šฉ ๊ฐ€๋Šฅ๋„%=100โˆ’๊ณผ์ ํ•ฉ์œ„ํ—˜%. DB ์ ์šฉ ๋ฒ„ํŠผ ํ™œ์„ฑ ์กฐ๊ฑด(gated PnL>0)๊ณผ๋Š” ๋ณ„๊ฐœ์ž…๋‹ˆ๋‹ค._ + +## ์ตœ์ข… ์„ ํƒ ํ›„๋ณด (๊ทœ์น™ ยท DB ์ ์šฉ ์ „ ํ™•์ธ) +- ์•„๋ž˜๋Š” **์—ญํ• ์ด ๋‹ค๋ฅธ** 4์ข… ํ›„๋ณด์ž…๋‹ˆ๋‹ค. mode Top10 1์œ„ โ‰  ์ต์ ˆ ๋Œ€ํ‘œ ยท **DB 1์ˆœ์œ„๋Š” ์‚ฌํ›„ํ•ฉ๊ฒฉ(gated)** ์ž…๋‹ˆ๋‹ค. +- mode pool: `positive` ยท scoring: `band_proximity_p25_p75` + +### ํ›„๋ณด 4์ข… +- **โ‘  ์‚ฌํ›„ํ•ฉ๊ฒฉ 1์œ„ (apply: gated)** (trial #163): PnL 127,091์› ยท WR 84.7% ยท PF 2.59 ยท ๊ฑฐ๋ž˜ 98๊ฑด ยท ์•ˆ์ •์ ์ˆ˜ -7949 ยท ํ˜ธ๊ฐ€ON spr2.0 r0.85 askร—31 ยท ํœฉ์˜ON sub60s lb180s dip0.10% tol0.25% +- **โ‘ก ์•ˆ์ • 1์œ„ (apply: stable)** (trial #117): PnL 50,988์› ยท WR 68.8% ยท PF 3.18 ยท ๊ฑฐ๋ž˜ 32๊ฑด ยท ์•ˆ์ •์ ์ˆ˜ 17293 ยท ํ˜ธ๊ฐ€OFF ยท ํœฉ์˜ON sub30s lb180s dip0.60% tol0.20% +- **โ‘ข mode_combo (apply: mode)** (trial ์—†์Œ(์กฐ๋ฆฝ)): PnL 0์› ยท WR 0.0% ยท PF 0.00 ยท ๊ฑฐ๋ž˜ 0๊ฑด ยท ํ˜ธ๊ฐ€ON spr5.4 r1.25 askร—32 ยท ํœฉ์˜ON sub30s lb180s dip0.10% tol0.15% +- **โ‘ฃ mode Top10 1์œ„ (apply: consensus ยท ๋ฐด๋“œ ์ „ํ˜• trial)** (trial #88): PnL 81,540์› ยท WR 76.3% ยท PF 2.42 ยท ๊ฑฐ๋ž˜ 38๊ฑด ยท ์•ˆ์ •์ ์ˆ˜ -5151 ยท ๊ทผ์ ‘ 98.0% (48/52์ถ• ๋ฐด๋“œ์•ˆ) ยท ํ˜ธ๊ฐ€ON spr4.0 r1.40 askร—27 ยท ํœฉ์˜ON sub30s lb180s dip0.40% tol0.25% +- mode Top10 meta: pool 125๊ฑด ยท ์ถ• 52๊ฐœ + +### ์ถ”์ฒœ (์ž๋™ ยท confirm ํ•„์ˆ˜) +1. **์‹ค๋งค DB ์ ์šฉ 1์ˆœ์œ„ โ†’ โ‘  ์‚ฌํ›„ํ•ฉ๊ฒฉ 1์œ„** (`optunaApply gated`) โ€” WR/PFยทmin_trades ์‚ฌํ›„ ํ†ต๊ณผ. +2. **๋ณ€๋™์„ฑยท์†์‹ค์ผ ์ค„์ด๊ธฐ โ†’ โ‘ก ์•ˆ์ • 1์œ„** (`stable`) โ€” PnL๋ณด๋‹ค ์ผ๋ณ„ ์•ˆ์ • ์šฐ์„  ์‹œ. +3. **2์ฐจ narrowยท๋Œ€ํ‘œ ์ˆซ์ž โ†’ โ‘ข mode_combo** โ€” ์ถ•๋ณ„ ์ตœ๋นˆ ์กฐ๋ฆฝ ยท trial ๋ฒˆํ˜ธ ์—†์Œ ยท ์ต์ ˆ์€ pool ์ตœ๋นˆ๊ฐ’ ์ฐธ๊ณ . +4. **โ‘ฃ mode Top10 1์œ„** โ€” ์–‘์ˆ˜ pool ์ „ํ˜• trial(๋‹ค์ถ• ๋ฐด๋“œ ๊ทผ์ ‘). **์ต์ ˆ ํ•˜๋‚˜๋กœ ์“ฐ์ง€ ๋ง ๊ฒƒ** ยท ํ‘œ์—์„œ ใ€Œ๋ณด๊ธฐใ€โ†’ consensus apply. + +## ์ด์ „ ์žฅ์—์„œ๋Š” +- ์‹ค๋งค ๋™๊ธฐ๊ฐ„ ์ฒญ์‚ฐ 8๊ฑด ยท ์Šน๋ฅ  50% ยท ํ•ฉ์‚ฐ PnL 121,682์› (๋ฐฑํ…Œ Optuna์™€ ์ˆซ์ž ๋‹ฌ๋ผ๋„ ์ •์ƒ โ€” ๊ณ ์ŠคํŠธยท์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑ ๊ฒฝ๋กœ ์ฐจ์ด). +- ์‚ฌํ›„ํ•ฉ๊ฒฉ 1์œ„: trial #163 ยท ๊ฑฐ๋ž˜ 98๊ฑด ยท ์Šน๋ฅ  84.7% ยท PF 2.59 ยท PnL 127,091์› +- ํ‘œ๋ณธ ์žฅ์ด 1์ผ๋ฟ์ด๋ผ, โ€˜์ด์ „ ์žฅ์— ์ž˜ ๋จนํžŒ ์ˆซ์žโ€™์ผ ๋ฟ **์ถ”์„ธ๊ฐ€ ๋ฐ”๋€Œ๋ฉด ๋ฐ”๋กœ ๊นจ์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.** + +## ์•ž์œผ๋กœ ์žฅ์—์„œ๋Š” +- **1~2์ผ Optuna best๋ฅผ ๋ฐ”๋กœ ์‹ค๋งค์— ๋„ฃ์ง€ ๋งˆ์„ธ์š”.** ๋‹ค์ผ(โ‰ฅ5๊ฑฐ๋ž˜์ผ) ์žฌ๊ฒ€์ฆยท์›น๋ฐฑํ…Œ 1ํšŒ ํ›„ ๊ฒ€ํ† . +- ์ ์šฉ ์‹œ์—๋Š” `results_gated` ํ›„๋ณด๋งŒ. ํƒ์ƒ‰์šฉ best(objective)์™€ ๋‹ค๋ฅผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. +- ์žฅ์ด ์ข์•„์ง€๊ฑฐ๋‚˜ ๋ณ€๋™์„ฑ์ด ์ปค์ง€๋ฉด: ์†์ ˆยทํŠธ๋ ˆ์ผยท์‹œ๊ฐ„์ฐฝ์ด ๋จผ์ € ๊นจ์ง‘๋‹ˆ๋‹ค. ์Šน๋ฅ  ์ž๋ž‘๋ณด๋‹ค **์†์ ˆ์ด ์‚ด์•„ ์žˆ๋Š”์ง€**๋ฅผ ๋ณด์„ธ์š”. +- ์‚ฌํ›„ํ•ฉ๊ฒฉ์ด ์žˆ์–ด๋„ โ€˜๋‚ด์ผ๋„ ๊ฐ™์€ ์žฅโ€™์ด ์•„๋‹™๋‹ˆ๋‹ค. ํŽ˜์ดํผ/์†Œ์•กยท๋ชจ์˜๋กœ 1~2์ผ ๊ด€์ฐฐ ํ›„ ํ™•๋Œ€ํ•˜์„ธ์š”. + +_์ƒ์„ฑ: 2026-09-05 00:14:59 (rule)_ + +## AI ์ฝ”๋ฉ˜ํŠธ (์ด์ „ ์žฅ / ์•ž์œผ๋กœ ์žฅ) [gemini] + +## ์ด์ „ ์žฅ์—์„œ๋Š” + +๋‹จ ํ•˜๋ฃจ(2026-09-04) ๋ฐ์ดํ„ฐ๋กœ Optuna ์ตœ์ ํ™”๊ฐ€ ์ง„ํ–‰๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ๋ฐฑํ…Œ์ŠคํŠธ ๊ฒฐ๊ณผ, ์‚ฌํ›„ํ•ฉ๊ฒฉ 1์œ„(#163)๊ฐ€ 98๊ฑด ๊ฑฐ๋ž˜์—์„œ 84.7%์˜ ๋†’์€ ์Šน๋ฅ ๊ณผ 2.59 PF๋ฅผ ๊ธฐ๋กํ•˜๋ฉฐ 12.7๋งŒ์›์˜ PnL์„ ๋ณด์˜€์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์ด๋Š” ๋‹จ์ผ ์žฅ์ผ ๋ฐฑํ…Œ์ŠคํŠธ๋กœ ๊ณผ์ ํ•ฉ ์œ„ํ—˜์ด 40%์— ๋‹ฌํ•˜๋ฉฐ, ์‹ค์ œ ์šด์˜(12.1๋งŒ์›)๊ณผ๋„ ๊ดด๋ฆฌ๊ฐ€ ์žˆ์–ด ํŠน์ • ์žฅ์„ธ์—๋งŒ ์šฐ์—ฐํžˆ ์ž˜ ๋งž์•˜์„ ๊ฐ€๋Šฅ์„ฑ์ด ๋งค์šฐ ํฝ๋‹ˆ๋‹ค. + +## ์•ž์œผ๋กœ ์žฅ์—์„œ๋Š” + +์ด๋ฒˆ 1์ผ ๋ฐฑํ…Œ์ŠคํŠธ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ”๋กœ ์‹ค๋งค์— ์ ์šฉํ•˜์ง€ ๋ง๊ณ , ์ตœ์†Œ 5์ผ ์ด์ƒ ๋‹ค์ผ ์žฌ๊ฒ€์ฆ ๋ฐ ์›น๋ฐฑํ…Œ์ŠคํŠธ๋ฅผ ๊ฑฐ์นœ ํ›„ ์†Œ์•ก/๋ชจ์˜ ํˆฌ์ž๋กœ ๊ด€์ฐฐํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๋ฐฑํ…Œ์ŠคํŠธ ์ƒ ์‚ฌํ›„ํ•ฉ๊ฒฉ(gated) ํ›„๋ณด๋งŒ ๊ฒ€ํ† ํ•˜๋˜, ์‹œ์žฅ ์ƒํ™ฉ ๋ณ€ํ™” ์‹œ ๋†’์€ ์Šน๋ฅ ๋ณด๋‹ค ์†์ ˆ๋งค ๊ธฐ๋Šฅ์ด ์ œ๋Œ€๋กœ ์ž‘๋™ํ•˜๋Š”์ง€ ์šฐ์„  ํ™•์ธํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๋ฐฑํ…Œ์ŠคํŠธ์™€ ์‹ค๋งค ๊ฐ„ ๊ณ ์ŠคํŠธ PnL ๋“ฑ ๊ดด๋ฆฌ๊ฐ€ ํฌ๊ณ  ํ™•์ • ์ˆ˜์ต์„ ์•ฝ์†ํ•  ์ˆ˜ ์—†์œผ๋ฏ€๋กœ, ํ•ญ์ƒ ์‹ ์ค‘ํ•˜๊ฒŒ ์ ‘๊ทผํ•˜์‹œ๊ธธ ๋ฐ”๋ž๋‹ˆ๋‹ค. diff --git a/kis_trader/backtest/results/optuna_tail_tpe_20260905_001843.briefing.md b/kis_trader/backtest/results/optuna_tail_tpe_20260905_001843.briefing.md new file mode 100644 index 0000000..49f8067 --- /dev/null +++ b/kis_trader/backtest/results/optuna_tail_tpe_20260905_001843.briefing.md @@ -0,0 +1,67 @@ +# Optuna ๋ธŒ๋ฆฌํ•‘ โ€” ๊ผฌ๋ฆฌ (tpe) +๊ธฐ๊ฐ„: 2026-09-04 ~ 2026-09-04 (๊ฑฐ๋ž˜์ผโ‰ˆ1์ผ) ยท trials 200/200 +ํƒ์ƒ‰ ๊ฒŒ์ดํŠธ: WRโ‰ฅ0% PFโ‰ฅ0 ยท min_tradesโ‰ฅ1 | ํ›„๋ณด ๊ฒŒ์ดํŠธ: WRโ‰ฅ40% PFโ‰ฅ1 ยท min_tradesโ‰ฅ1 +- min_trades=1: **ํ•ฉ๊ฒฉ ์ธ์ • ์ตœ์†Œ ๊ฑฐ๋ž˜ ๊ฑด์ˆ˜**(ํ‘œ๋ณธ ๋ถ€์กฑยท์šฐ์—ฐ ์Šน๋ฅ  ๋ฐฉ์ง€). ์ด๋ณด๋‹ค ์ ์€ ์กฐํ•ฉ์€ ํ•™์Šต/ํ›„๋ณด ์ง‘๊ณ„์—์„œ ์ œ์™ธ๋ฉ๋‹ˆ๋‹ค. +ํ•™์Šต์šฉ ํ†ต๊ณผ 158๊ฑด ยท ์‚ฌํ›„ํ•ฉ๊ฒฉ(results_gated) 115๊ฑด + +## ๊ณผ์ ํ•ฉยท์ ์šฉ ๊ฐ€๋Šฅ๋„ (ํœด๋ฆฌ์Šคํ‹ฑ) +- **๊ณผ์ ํ•ฉ ์œ„ํ—˜ 40.0%** ยท **์ ์šฉ ๊ฐ€๋Šฅ๋„ 60.0%** ยท ํŒ์ •: **์ฃผ์˜** โ€” ์ ์šฉ ๊ฐ€๋Šฅ๋„ ์ค‘๊ฐ„ โ€” ๋‹ค์ผ(โ‰ฅ5์ผ) ์žฌ๊ฒ€์ฆยท์›น๋ฐฑํ…Œ ํ›„ ์†Œ์•ก๋งŒ + - ํ‘œ๋ณธ ์žฅ์ผ: +40.0p โ€” ๊ฑฐ๋ž˜์ผโ‰ˆ1์ผ โ€” ๋‹จ์ผ ์žฅ ๊ณผ์ ํ•ฉ ์œ„ํ—˜ ์ตœ๋Œ€ + - ๊ฑฐ๋ž˜ ํ‘œ๋ณธ: +0.0p โ€” ์ƒ์œ„ ํ›„๋ณด ๊ฑฐ๋ž˜ 77๊ฑด โ€” ์ƒ๋Œ€์  ์–‘ํ˜ธ + - ์Šน๋ฅ ยทPF ์ด์ƒ์น˜: +0.0p โ€” ์ด์ƒ์น˜ ์—†์Œ + - ๊ฒŒ์ดํŠธ ์ปค๋ฒ„: +0.0p โ€” ์‚ฌํ›„ํ•ฉ๊ฒฉ 115๊ฑด ยท stable 10๊ฑด + - PnL ๊ณ ์›: +0.0p โ€” ๊ณ ์› ๋น„์œจ 1% (1๊ฑด) +- ์ž„๊ณ„๊ฐ’ ๋ถ„ํฌ ํ‘œ๋ณธ: results_gated ์ƒ์œ„ 30๊ฑด +| ํŒŒ๋ผ๋ฏธํ„ฐ | median | p25~p75 | mode(๋น„์œจ) | +|---|---:|---|---| +| `entry_mode` | โ€” | โ€” | align (100%) | +| `cand_limit` | 20.0 | 5.0 ~ 20.0 | 20 (73%) | +| `max_daily_change` | 26.5 | 21.25 ~ 32.0 | 17.0 (10%) | +| `min_drop_rate` | 0.01 | 0.005 ~ 0.02 | 0.005 (40%) | +| `min_recovery_ratio` | 0.155 | 0.13 ~ 0.18 | 0.15 (17%) | +| `tail_ratio_min` | 0.55 | 0.425 ~ 0.8 | 0.4 (27%) | +| `tail_pct_min` | 0.00325 | 0.002 ~ 0.006 | 0.002 (13%) | +| `max_rec_3m` | 0.825 | 0.7925 ~ 0.8875 | 0.89 (17%) | +| `shoulder_min_high` | 0.0025 | 0.002 ~ 0.003 | 0.002 (50%) | +| `shoulder_cut_pct` | 0.001 | 0.0005 ~ 0.0015 | 0.0005 (37%) | +| `stop_atr_mult` | 2.6 | 2.4 ~ 2.8 | 2.9 (20%) | +| `target_atr_mult` | 1.6 | 1.3 ~ 1.8 | 1.2 (13%) | +- _์ฐธ๊ณ : ๊ณผ์ ํ•ฉ%๋Š” ๊ต์ฐจ๊ฒ€์ฆ ์ ์ˆ˜๊ฐ€ ์•„๋‹ˆ๋ผ ํ‘œ๋ณธยท์ด์ƒ์น˜ยท๊ณ ์› ํœด๋ฆฌ์Šคํ‹ฑ์ž…๋‹ˆ๋‹ค. ์ ์šฉ ๊ฐ€๋Šฅ๋„%=100โˆ’๊ณผ์ ํ•ฉ์œ„ํ—˜%. DB ์ ์šฉ ๋ฒ„ํŠผ ํ™œ์„ฑ ์กฐ๊ฑด(gated PnL>0)๊ณผ๋Š” ๋ณ„๊ฐœ์ž…๋‹ˆ๋‹ค._ + +## ์ตœ์ข… ์„ ํƒ ํ›„๋ณด (๊ทœ์น™ ยท DB ์ ์šฉ ์ „ ํ™•์ธ) +- ์•„๋ž˜๋Š” **์—ญํ• ์ด ๋‹ค๋ฅธ** 4์ข… ํ›„๋ณด์ž…๋‹ˆ๋‹ค. mode Top10 1์œ„ โ‰  ์ต์ ˆ ๋Œ€ํ‘œ ยท **DB 1์ˆœ์œ„๋Š” ์‚ฌํ›„ํ•ฉ๊ฒฉ(gated)** ์ž…๋‹ˆ๋‹ค. +- mode pool: `positive` ยท scoring: `band_proximity_p25_p75` + +### ํ›„๋ณด 4์ข… +- **โ‘  ์‚ฌํ›„ํ•ฉ๊ฒฉ 1์œ„ (apply: gated)** (trial #192): PnL 110,719์› ยท WR 81.8% ยท PF 2.57 ยท ๊ฑฐ๋ž˜ 77๊ฑด ยท ์•ˆ์ •์ ์ˆ˜ -7324 ยท ํ˜ธ๊ฐ€ON spr0.2 r1.50 askร—13 ยท ํœฉ์˜OFF +- **โ‘ก ์•ˆ์ • 1์œ„ (apply: stable)** (trial #174): PnL 36,202์› ยท WR 57.7% ยท PF 2.50 ยท ๊ฑฐ๋ž˜ 26๊ฑด ยท ์•ˆ์ •์ ์ˆ˜ 13324 ยท ํ˜ธ๊ฐ€OFF ยท ํœฉ์˜OFF +- **โ‘ข mode_combo (apply: mode)** (trial ์—†์Œ(์กฐ๋ฆฝ)): PnL 0์› ยท WR 0.0% ยท PF 0.00 ยท ๊ฑฐ๋ž˜ 0๊ฑด ยท ํ˜ธ๊ฐ€ON spr1.6 r1.30 askร—33 ยท ํœฉ์˜OFF +- **โ‘ฃ mode Top10 1์œ„ (apply: consensus ยท ๋ฐด๋“œ ์ „ํ˜• trial)** (trial #76): PnL 39,963์› ยท WR 84.0% ยท PF 3.00 ยท ๊ฑฐ๋ž˜ 25๊ฑด ยท ์•ˆ์ •์ ์ˆ˜ 8266 ยท ๊ทผ์ ‘ 97.9% (46/52์ถ• ๋ฐด๋“œ์•ˆ) ยท ํ˜ธ๊ฐ€ON spr0.3 r1.25 askร—42 ยท ํœฉ์˜OFF +- mode Top10 meta: pool 116๊ฑด ยท ์ถ• 52๊ฐœ + +### ์ถ”์ฒœ (์ž๋™ ยท confirm ํ•„์ˆ˜) +1. **์‹ค๋งค DB ์ ์šฉ 1์ˆœ์œ„ โ†’ โ‘  ์‚ฌํ›„ํ•ฉ๊ฒฉ 1์œ„** (`optunaApply gated`) โ€” WR/PFยทmin_trades ์‚ฌํ›„ ํ†ต๊ณผ. +2. **๋ณ€๋™์„ฑยท์†์‹ค์ผ ์ค„์ด๊ธฐ โ†’ โ‘ก ์•ˆ์ • 1์œ„** (`stable`) โ€” PnL๋ณด๋‹ค ์ผ๋ณ„ ์•ˆ์ • ์šฐ์„  ์‹œ. +3. **2์ฐจ narrowยท๋Œ€ํ‘œ ์ˆซ์ž โ†’ โ‘ข mode_combo** โ€” ์ถ•๋ณ„ ์ตœ๋นˆ ์กฐ๋ฆฝ ยท trial ๋ฒˆํ˜ธ ์—†์Œ ยท ์ต์ ˆ์€ pool ์ตœ๋นˆ๊ฐ’ ์ฐธ๊ณ . +4. **โ‘ฃ mode Top10 1์œ„** โ€” ์–‘์ˆ˜ pool ์ „ํ˜• trial(๋‹ค์ถ• ๋ฐด๋“œ ๊ทผ์ ‘). **์ต์ ˆ ํ•˜๋‚˜๋กœ ์“ฐ์ง€ ๋ง ๊ฒƒ** ยท ํ‘œ์—์„œ ใ€Œ๋ณด๊ธฐใ€โ†’ consensus apply. + +## ์ด์ „ ์žฅ์—์„œ๋Š” +- ์‹ค๋งค ๋™๊ธฐ๊ฐ„ ์ฒญ์‚ฐ 8๊ฑด ยท ์Šน๋ฅ  50% ยท ํ•ฉ์‚ฐ PnL 121,682์› (๋ฐฑํ…Œ Optuna์™€ ์ˆซ์ž ๋‹ฌ๋ผ๋„ ์ •์ƒ โ€” ๊ณ ์ŠคํŠธยท์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑ ๊ฒฝ๋กœ ์ฐจ์ด). +- ์‚ฌํ›„ํ•ฉ๊ฒฉ 1์œ„: trial #192 ยท ๊ฑฐ๋ž˜ 77๊ฑด ยท ์Šน๋ฅ  81.8% ยท PF 2.57 ยท PnL 110,719์› +- ํ‘œ๋ณธ ์žฅ์ด 1์ผ๋ฟ์ด๋ผ, โ€˜์ด์ „ ์žฅ์— ์ž˜ ๋จนํžŒ ์ˆซ์žโ€™์ผ ๋ฟ **์ถ”์„ธ๊ฐ€ ๋ฐ”๋€Œ๋ฉด ๋ฐ”๋กœ ๊นจ์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.** + +## ์•ž์œผ๋กœ ์žฅ์—์„œ๋Š” +- **1~2์ผ Optuna best๋ฅผ ๋ฐ”๋กœ ์‹ค๋งค์— ๋„ฃ์ง€ ๋งˆ์„ธ์š”.** ๋‹ค์ผ(โ‰ฅ5๊ฑฐ๋ž˜์ผ) ์žฌ๊ฒ€์ฆยท์›น๋ฐฑํ…Œ 1ํšŒ ํ›„ ๊ฒ€ํ† . +- ์ ์šฉ ์‹œ์—๋Š” `results_gated` ํ›„๋ณด๋งŒ. ํƒ์ƒ‰์šฉ best(objective)์™€ ๋‹ค๋ฅผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. +- ์žฅ์ด ์ข์•„์ง€๊ฑฐ๋‚˜ ๋ณ€๋™์„ฑ์ด ์ปค์ง€๋ฉด: ์†์ ˆยทํŠธ๋ ˆ์ผยท์‹œ๊ฐ„์ฐฝ์ด ๋จผ์ € ๊นจ์ง‘๋‹ˆ๋‹ค. ์Šน๋ฅ  ์ž๋ž‘๋ณด๋‹ค **์†์ ˆ์ด ์‚ด์•„ ์žˆ๋Š”์ง€**๋ฅผ ๋ณด์„ธ์š”. +- ์‚ฌํ›„ํ•ฉ๊ฒฉ์ด ์žˆ์–ด๋„ โ€˜๋‚ด์ผ๋„ ๊ฐ™์€ ์žฅโ€™์ด ์•„๋‹™๋‹ˆ๋‹ค. ํŽ˜์ดํผ/์†Œ์•กยท๋ชจ์˜๋กœ 1~2์ผ ๊ด€์ฐฐ ํ›„ ํ™•๋Œ€ํ•˜์„ธ์š”. + +_์ƒ์„ฑ: 2026-09-05 00:18:45 (rule)_ + +## AI ์ฝ”๋ฉ˜ํŠธ (์ด์ „ ์žฅ / ์•ž์œผ๋กœ ์žฅ) [gemini] + +ใ€Œ์ด์ „ ์žฅ์—์„œ๋Š”ใ€ +์ง€๋‚œ ์žฅ ์‹ค๋งค๋Š” 8๊ฑด ์ฒญ์‚ฐ, PnL 121,682์›์ด์—ˆ๊ณ , ๋ฐฑํ…Œ์ŠคํŠธ Optuna ์‚ฌํ›„ํ•ฉ๊ฒฉ 1์œ„๋Š” 77๊ฑด ๊ฑฐ๋ž˜์— PnL 110,719์›, ์Šน๋ฅ  81.8%๋ฅผ ๊ธฐ๋กํ–ˆ์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์ด๋Š” **๋‹จ ํ•˜๋ฃจ์น˜ ๋ฐ์ดํ„ฐ**๋กœ, **๊ณผ์ ํ•ฉ ์œ„ํ—˜์ด ๋งค์šฐ ๋†’์Šต๋‹ˆ๋‹ค.** ์ง€๋‚œ ์žฅ์— ์šฐ์—ฐํžˆ ์ž˜ ๋งž์€ ์ˆซ์ž์ผ ๋ฟ, ์‹œ์žฅ ๋ณ€ํ™”์— ๋ฐ”๋กœ ๊นจ์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์‹ค๋งค์™€ ๋ฐฑํ…Œ์ŠคํŠธ ๊ฐ„ ๊ดด๋ฆฌ๋„ ์—ผ๋‘์— ๋‘์„ธ์š”. + +ใ€Œ์•ž์œผ๋กœ ์žฅ์—์„œ๋Š”ใ€ +**๋‹จ์ผ ์žฅ Optuna ๊ฒฐ๊ณผ๋Š” ์ฆ‰์‹œ ์‹ค๋งค ์ ์šฉ์„ ๊ธˆํ•ฉ๋‹ˆ๋‹ค.** ์ตœ์†Œ 5๊ฑฐ๋ž˜์ผ ์ด์ƒ ์žฌ๊ฒ€์ฆ ๋˜๋Š” ์›น๋ฐฑํ…Œ์ŠคํŠธ ํ›„ ๊ฒ€ํ† ํ•˜์‹ญ์‹œ์˜ค. ์ ์šฉ ์‹œ `results_gated` ํ›„๋ณด๋งŒ ์‹ ์ค‘ํžˆ ๊ณ ๋ คํ•˜๋ฉฐ, mode Top10 1์œ„๋Š” ์ต์ ˆ ๋Œ€ํ‘œ๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค. ์‹œ์žฅ ๋ณ€๋™์„ฑ ์ฆ๊ฐ€๋Š” ์†์ ˆ ๊ธฐ๋Šฅ์„ ๋จผ์ € ๋ฌด๋ ฅํ™”ํ•  ์ˆ˜ ์žˆ์œผ๋‹ˆ **์Šน๋ฅ ๋ณด๋‹ค ์†์ ˆ์ด ์‚ด์•„์žˆ๋Š”์ง€** ํ™•์ธํ•˜์„ธ์š”. ์‹ค๋งคโ†”๋ฐฑํ…Œ์ŠคํŠธ **๊ณ ์ŠคํŠธํผ์ง€** ๋“ฑ ๊ดด๋ฆฌ๋ฅผ ์ธ์ •ํ•˜๊ณ , ํŽ˜์ดํผ/์†Œ์•ก์œผ๋กœ ์ถฉ๋ถ„ํžˆ ๊ด€์ฐฐ ํ›„ ํ™•๋Œ€ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. diff --git a/kis_trader/backtest/results/optuna_tail_tpe_20260905_010030.briefing.md b/kis_trader/backtest/results/optuna_tail_tpe_20260905_010030.briefing.md new file mode 100644 index 0000000..051bc40 --- /dev/null +++ b/kis_trader/backtest/results/optuna_tail_tpe_20260905_010030.briefing.md @@ -0,0 +1,69 @@ +# Optuna ๋ธŒ๋ฆฌํ•‘ โ€” ๊ผฌ๋ฆฌ (tpe) +๊ธฐ๊ฐ„: 2026-09-04 ~ 2026-09-04 (๊ฑฐ๋ž˜์ผโ‰ˆ1์ผ) ยท trials 200/200 +ํƒ์ƒ‰ ๊ฒŒ์ดํŠธ: WRโ‰ฅ0% PFโ‰ฅ0 ยท min_tradesโ‰ฅ1 | ํ›„๋ณด ๊ฒŒ์ดํŠธ: WRโ‰ฅ40% PFโ‰ฅ1 ยท min_tradesโ‰ฅ1 +- min_trades=1: **ํ•ฉ๊ฒฉ ์ธ์ • ์ตœ์†Œ ๊ฑฐ๋ž˜ ๊ฑด์ˆ˜**(ํ‘œ๋ณธ ๋ถ€์กฑยท์šฐ์—ฐ ์Šน๋ฅ  ๋ฐฉ์ง€). ์ด๋ณด๋‹ค ์ ์€ ์กฐํ•ฉ์€ ํ•™์Šต/ํ›„๋ณด ์ง‘๊ณ„์—์„œ ์ œ์™ธ๋ฉ๋‹ˆ๋‹ค. +ํ•™์Šต์šฉ ํ†ต๊ณผ 171๊ฑด ยท ์‚ฌํ›„ํ•ฉ๊ฒฉ(results_gated) 116๊ฑด + +## ๊ณผ์ ํ•ฉยท์ ์šฉ ๊ฐ€๋Šฅ๋„ (ํœด๋ฆฌ์Šคํ‹ฑ) +- **๊ณผ์ ํ•ฉ ์œ„ํ—˜ 40.0%** ยท **์ ์šฉ ๊ฐ€๋Šฅ๋„ 60.0%** ยท ํŒ์ •: **์ฃผ์˜** โ€” ์ ์šฉ ๊ฐ€๋Šฅ๋„ ์ค‘๊ฐ„ โ€” ๋‹ค์ผ(โ‰ฅ5์ผ) ์žฌ๊ฒ€์ฆยท์›น๋ฐฑํ…Œ ํ›„ ์†Œ์•ก๋งŒ + - ํ‘œ๋ณธ ์žฅ์ผ: +40.0p โ€” ๊ฑฐ๋ž˜์ผโ‰ˆ1์ผ โ€” ๋‹จ์ผ ์žฅ ๊ณผ์ ํ•ฉ ์œ„ํ—˜ ์ตœ๋Œ€ + - ๊ฑฐ๋ž˜ ํ‘œ๋ณธ: +0.0p โ€” ์ƒ์œ„ ํ›„๋ณด ๊ฑฐ๋ž˜ 142๊ฑด โ€” ์ƒ๋Œ€์  ์–‘ํ˜ธ + - ์Šน๋ฅ ยทPF ์ด์ƒ์น˜: +0.0p โ€” ์ด์ƒ์น˜ ์—†์Œ + - ๊ฒŒ์ดํŠธ ์ปค๋ฒ„: +0.0p โ€” ์‚ฌํ›„ํ•ฉ๊ฒฉ 116๊ฑด ยท stable 10๊ฑด + - PnL ๊ณ ์›: +0.0p โ€” ๊ณ ์› ๋น„์œจ 1% (1๊ฑด) +- ์ž„๊ณ„๊ฐ’ ๋ถ„ํฌ ํ‘œ๋ณธ: results_gated ์ƒ์œ„ 30๊ฑด +| ํŒŒ๋ผ๋ฏธํ„ฐ | median | p25~p75 | mode(๋น„์œจ) | +|---|---:|---|---| +| `entry_mode` | โ€” | โ€” | align (100%) | +| `cand_limit` | 0.0 | 0.0 ~ 0.0 | 0 (80%) | +| `max_daily_change` | 26.5 | 19.0 ~ 32.5 | 19.0 (17%) | +| `min_drop_rate` | 0.01 | 0.005 ~ 0.01 | 0.01 (43%) | +| `min_recovery_ratio` | 0.22 | 0.1625 ~ 0.27 | 0.22 (10%) | +| `tail_ratio_min` | 0.7 | 0.525 ~ 0.8 | 0.6 (20%) | +| `tail_pct_min` | 0.005 | 0.003625 ~ 0.007 | 0.005 (17%) | +| `max_rec_3m` | 0.845 | 0.74 ~ 0.895 | 0.9 (10%) | +| `shoulder_min_high` | 0.004 | 0.003 ~ 0.00575 | 0.004 (30%) | +| `shoulder_cut_pct` | 0.001 | 0.0005 ~ 0.001875 | 0.0005 (37%) | +| `stop_atr_mult` | 1.45 | 1.125 ~ 2.45 | 1.2 (17%) | +| `target_atr_mult` | 3.05 | 2.8 ~ 3.375 | 3.5 (17%) | +- _์ฐธ๊ณ : ๊ณผ์ ํ•ฉ%๋Š” ๊ต์ฐจ๊ฒ€์ฆ ์ ์ˆ˜๊ฐ€ ์•„๋‹ˆ๋ผ ํ‘œ๋ณธยท์ด์ƒ์น˜ยท๊ณ ์› ํœด๋ฆฌ์Šคํ‹ฑ์ž…๋‹ˆ๋‹ค. ์ ์šฉ ๊ฐ€๋Šฅ๋„%=100โˆ’๊ณผ์ ํ•ฉ์œ„ํ—˜%. DB ์ ์šฉ ๋ฒ„ํŠผ ํ™œ์„ฑ ์กฐ๊ฑด(gated PnL>0)๊ณผ๋Š” ๋ณ„๊ฐœ์ž…๋‹ˆ๋‹ค._ + +## ์ตœ์ข… ์„ ํƒ ํ›„๋ณด (๊ทœ์น™ ยท DB ์ ์šฉ ์ „ ํ™•์ธ) +- ์•„๋ž˜๋Š” **์—ญํ• ์ด ๋‹ค๋ฅธ** 4์ข… ํ›„๋ณด์ž…๋‹ˆ๋‹ค. mode Top10 1์œ„ โ‰  ์ต์ ˆ ๋Œ€ํ‘œ ยท **DB 1์ˆœ์œ„๋Š” ์‚ฌํ›„ํ•ฉ๊ฒฉ(gated)** ์ž…๋‹ˆ๋‹ค. +- mode pool: `positive` ยท scoring: `band_proximity_p25_p75` + +### ํ›„๋ณด 4์ข… +- **โ‘  ์‚ฌํ›„ํ•ฉ๊ฒฉ 1์œ„ (apply: gated)** (trial #105): PnL 105,326์› ยท WR 73.2% ยท PF 1.67 ยท ๊ฑฐ๋ž˜ 142๊ฑด ยท ์•ˆ์ •์ ์ˆ˜ -4353 ยท ํ˜ธ๊ฐ€OFF ยท ํœฉ์˜ON sub15s lb180s dip0.90% tol0.20% +- **โ‘ก ์•ˆ์ • 1์œ„ (apply: stable)** (trial #72): PnL 31,331์› ยท WR 67.9% ยท PF 1.74 ยท ๊ฑฐ๋ž˜ 28๊ฑด ยท ์•ˆ์ •์ ์ˆ˜ 9316 ยท ํ˜ธ๊ฐ€ON spr0.3 r1.30 askร—71 ยท ํœฉ์˜ON sub15s lb120s dip0.90% tol0.30% +- **โ‘ข mode_combo (apply: mode)** (trial ์—†์Œ(์กฐ๋ฆฝ)): PnL 0์› ยท WR 0.0% ยท PF 0.00 ยท ๊ฑฐ๋ž˜ 0๊ฑด ยท ํ˜ธ๊ฐ€ON spr0.4 r1.40 askร—32 ยท ํœฉ์˜OFF +- **โ‘ฃ mode Top10 1์œ„ (apply: consensus ยท ๋ฐด๋“œ ์ „ํ˜• trial)** (trial #54): PnL 45,511์› ยท WR 77.8% ยท PF 1.76 ยท ๊ฑฐ๋ž˜ 45๊ฑด ยท ์•ˆ์ •์ ์ˆ˜ -5126 ยท ๊ทผ์ ‘ 96.8% (45/52์ถ• ๋ฐด๋“œ์•ˆ) ยท ํ˜ธ๊ฐ€OFF ยท ํœฉ์˜OFF +- mode Top10 meta: pool 116๊ฑด ยท ์ถ• 52๊ฐœ + +### ์ถ”์ฒœ (์ž๋™ ยท confirm ํ•„์ˆ˜) +1. **์‹ค๋งค DB ์ ์šฉ 1์ˆœ์œ„ โ†’ โ‘  ์‚ฌํ›„ํ•ฉ๊ฒฉ 1์œ„** (`optunaApply gated`) โ€” WR/PFยทmin_trades ์‚ฌํ›„ ํ†ต๊ณผ. +2. **๋ณ€๋™์„ฑยท์†์‹ค์ผ ์ค„์ด๊ธฐ โ†’ โ‘ก ์•ˆ์ • 1์œ„** (`stable`) โ€” PnL๋ณด๋‹ค ์ผ๋ณ„ ์•ˆ์ • ์šฐ์„  ์‹œ. +3. **2์ฐจ narrowยท๋Œ€ํ‘œ ์ˆซ์ž โ†’ โ‘ข mode_combo** โ€” ์ถ•๋ณ„ ์ตœ๋นˆ ์กฐ๋ฆฝ ยท trial ๋ฒˆํ˜ธ ์—†์Œ ยท ์ต์ ˆ์€ pool ์ตœ๋นˆ๊ฐ’ ์ฐธ๊ณ . +4. **โ‘ฃ mode Top10 1์œ„** โ€” ์–‘์ˆ˜ pool ์ „ํ˜• trial(๋‹ค์ถ• ๋ฐด๋“œ ๊ทผ์ ‘). **์ต์ ˆ ํ•˜๋‚˜๋กœ ์“ฐ์ง€ ๋ง ๊ฒƒ** ยท ํ‘œ์—์„œ ใ€Œ๋ณด๊ธฐใ€โ†’ consensus apply. + +## ์ด์ „ ์žฅ์—์„œ๋Š” +- ์‹ค๋งค ๋™๊ธฐ๊ฐ„ ์ฒญ์‚ฐ 8๊ฑด ยท ์Šน๋ฅ  50% ยท ํ•ฉ์‚ฐ PnL 121,682์› (๋ฐฑํ…Œ Optuna์™€ ์ˆซ์ž ๋‹ฌ๋ผ๋„ ์ •์ƒ โ€” ๊ณ ์ŠคํŠธยท์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑ ๊ฒฝ๋กœ ์ฐจ์ด). +- ์‚ฌํ›„ํ•ฉ๊ฒฉ 1์œ„: trial #105 ยท ๊ฑฐ๋ž˜ 142๊ฑด ยท ์Šน๋ฅ  73.2% ยท PF 1.67 ยท PnL 105,326์› +- ํ‘œ๋ณธ ์žฅ์ด 1์ผ๋ฟ์ด๋ผ, โ€˜์ด์ „ ์žฅ์— ์ž˜ ๋จนํžŒ ์ˆซ์žโ€™์ผ ๋ฟ **์ถ”์„ธ๊ฐ€ ๋ฐ”๋€Œ๋ฉด ๋ฐ”๋กœ ๊นจ์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.** + +## ์•ž์œผ๋กœ ์žฅ์—์„œ๋Š” +- **1~2์ผ Optuna best๋ฅผ ๋ฐ”๋กœ ์‹ค๋งค์— ๋„ฃ์ง€ ๋งˆ์„ธ์š”.** ๋‹ค์ผ(โ‰ฅ5๊ฑฐ๋ž˜์ผ) ์žฌ๊ฒ€์ฆยท์›น๋ฐฑํ…Œ 1ํšŒ ํ›„ ๊ฒ€ํ† . +- ์ ์šฉ ์‹œ์—๋Š” `results_gated` ํ›„๋ณด๋งŒ. ํƒ์ƒ‰์šฉ best(objective)์™€ ๋‹ค๋ฅผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. +- ์žฅ์ด ์ข์•„์ง€๊ฑฐ๋‚˜ ๋ณ€๋™์„ฑ์ด ์ปค์ง€๋ฉด: ์†์ ˆยทํŠธ๋ ˆ์ผยท์‹œ๊ฐ„์ฐฝ์ด ๋จผ์ € ๊นจ์ง‘๋‹ˆ๋‹ค. ์Šน๋ฅ  ์ž๋ž‘๋ณด๋‹ค **์†์ ˆ์ด ์‚ด์•„ ์žˆ๋Š”์ง€**๋ฅผ ๋ณด์„ธ์š”. +- ์‚ฌํ›„ํ•ฉ๊ฒฉ์ด ์žˆ์–ด๋„ โ€˜๋‚ด์ผ๋„ ๊ฐ™์€ ์žฅโ€™์ด ์•„๋‹™๋‹ˆ๋‹ค. ํŽ˜์ดํผ/์†Œ์•กยท๋ชจ์˜๋กœ 1~2์ผ ๊ด€์ฐฐ ํ›„ ํ™•๋Œ€ํ•˜์„ธ์š”. + +_์ƒ์„ฑ: 2026-09-05 01:00:32 (rule)_ + +## AI ์ฝ”๋ฉ˜ํŠธ (์ด์ „ ์žฅ / ์•ž์œผ๋กœ ์žฅ) [gemini] + +### ์ด์ „ ์žฅ์—์„œ๋Š” + +์ด์ „ ์‹ค์ œ ๊ฑฐ๋ž˜์—์„œ๋Š” 8๊ฑด ์ฒญ์‚ฐ, ์Šน๋ฅ  50%, ํ•ฉ์‚ฐ PnL 121,682์›์„ ๊ธฐ๋กํ–ˆ์Šต๋‹ˆ๋‹ค. Optuna ๋ฐฑํ…Œ์ŠคํŠธ ์ƒ ์‚ฌํ›„ ํ•ฉ๊ฒฉ๋œ 1์œ„ ์ „๋žต(trial #105)์€ 142๊ฑด ๊ฑฐ๋ž˜์—์„œ ์Šน๋ฅ  73.2%, PF 1.67, PnL 105,326์›์„ ๋ณด์˜€์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์ด๋Š” ๋‹จ ํ•˜๋ฃจ์˜ ๋ฐฑํ…Œ์ŠคํŠธ ๊ฒฐ๊ณผ๋กœ, '๋‹จ์ผ ์žฅ ์šฐ์—ฐํ•œ ์„ฑ๊ณต'์ผ ๊ฐ€๋Šฅ์„ฑ์ด ๋งค์šฐ ๋†’์œผ๋ฉฐ ๊ณผ์ ํ•ฉ ์œ„ํ—˜(40%)์ด ํฝ๋‹ˆ๋‹ค. ๋ฐฑํ…Œ์ŠคํŠธ์™€ ์‹ค๋งค ๊ฐ„์—๋Š” ์œ ๋‹ˆ๋ฒ„์Šค, ํ‹ฑ ๊ฒฝ๋กœ ์ฐจ์ด ๋“ฑ์œผ๋กœ ์ธํ•œ ๊ดด๋ฆฌ๊ฐ€ ํ•ญ์ƒ ์กด์žฌํ•ฉ๋‹ˆ๋‹ค. + +### ์•ž์œผ๋กœ ์žฅ์—์„œ๋Š” + +๋‹จ์ผ ์žฅ์ผ(1์ผ) Optuna ๊ฒฐ๊ณผ๋Š” ์ฆ‰์‹œ ์‹ค๋งค ์ ์šฉ์— ์‹ ์ค‘ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ตœ์†Œ 5์ผ ์ด์ƒ์˜ ๋‹ค์ผ ์žฌ๊ฒ€์ฆ๊ณผ ์›น๋ฐฑํ…Œ์ŠคํŠธ๋ฅผ ํ†ตํ•ด ๊ฒ€์ฆ์ด ํ•„์ˆ˜์ ์ž…๋‹ˆ๋‹ค. ์ ์šฉ ์‹œ์—๋Š” `results_gated`๋กœ ํ•„ํ„ฐ๋ง๋œ ํ›„๋ณด๋ฅผ ์šฐ์„  ๊ฒ€ํ† ํ•˜๋ฉฐ, 'mode Top10 1์œ„'๊ฐ€ ์ต์ ˆ ๋Œ€ํ‘œ๊ฐ€ ์•„๋‹˜์„ ๋ช…์‹ฌํ•˜์„ธ์š”. DB 1์ˆœ์œ„๋Š” ์‚ฌํ›„ํ•ฉ๊ฒฉ(gated)๋œ ์ „๋žต์ž…๋‹ˆ๋‹ค. ์‹œ์žฅ ๋ณ€๋™์„ฑ์ด ์ปค์ง€๋ฉด ์Šน๋ฅ ๋ณด๋‹ค ์†์ ˆ๋งค ์ž‘๋™ ์—ฌ๋ถ€๊ฐ€ ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค. ํ™•์ • ์ˆ˜์ต์„ ์•ฝ์†ํ•  ์ˆ˜ ์—†์œผ๋ฉฐ, ํŽ˜์ดํผ/์†Œ์•ก ๋ชจ์˜ํˆฌ์ž๋กœ 1~2์ผ ๊ด€์ฐฐ ํ›„ ์ ์ง„์  ํ™•๋Œ€๋ฅผ ๊ถŒ๊ณ ํ•ฉ๋‹ˆ๋‹ค. diff --git a/kis_trader/backtest/results/optuna_tail_tpe_20260905_010412.briefing.md b/kis_trader/backtest/results/optuna_tail_tpe_20260905_010412.briefing.md new file mode 100644 index 0000000..726b62e --- /dev/null +++ b/kis_trader/backtest/results/optuna_tail_tpe_20260905_010412.briefing.md @@ -0,0 +1,69 @@ +# Optuna ๋ธŒ๋ฆฌํ•‘ โ€” ๊ผฌ๋ฆฌ (tpe) +๊ธฐ๊ฐ„: 2026-09-04 ~ 2026-09-04 (๊ฑฐ๋ž˜์ผโ‰ˆ1์ผ) ยท trials 200/200 +ํƒ์ƒ‰ ๊ฒŒ์ดํŠธ: WRโ‰ฅ0% PFโ‰ฅ0 ยท min_tradesโ‰ฅ1 | ํ›„๋ณด ๊ฒŒ์ดํŠธ: WRโ‰ฅ40% PFโ‰ฅ1 ยท min_tradesโ‰ฅ1 +- min_trades=1: **ํ•ฉ๊ฒฉ ์ธ์ • ์ตœ์†Œ ๊ฑฐ๋ž˜ ๊ฑด์ˆ˜**(ํ‘œ๋ณธ ๋ถ€์กฑยท์šฐ์—ฐ ์Šน๋ฅ  ๋ฐฉ์ง€). ์ด๋ณด๋‹ค ์ ์€ ์กฐํ•ฉ์€ ํ•™์Šต/ํ›„๋ณด ์ง‘๊ณ„์—์„œ ์ œ์™ธ๋ฉ๋‹ˆ๋‹ค. +ํ•™์Šต์šฉ ํ†ต๊ณผ 139๊ฑด ยท ์‚ฌํ›„ํ•ฉ๊ฒฉ(results_gated) 50๊ฑด + +## ๊ณผ์ ํ•ฉยท์ ์šฉ ๊ฐ€๋Šฅ๋„ (ํœด๋ฆฌ์Šคํ‹ฑ) +- **๊ณผ์ ํ•ฉ ์œ„ํ—˜ 40.0%** ยท **์ ์šฉ ๊ฐ€๋Šฅ๋„ 60.0%** ยท ํŒ์ •: **์ฃผ์˜** โ€” ์ ์šฉ ๊ฐ€๋Šฅ๋„ ์ค‘๊ฐ„ โ€” ๋‹ค์ผ(โ‰ฅ5์ผ) ์žฌ๊ฒ€์ฆยท์›น๋ฐฑํ…Œ ํ›„ ์†Œ์•ก๋งŒ + - ํ‘œ๋ณธ ์žฅ์ผ: +40.0p โ€” ๊ฑฐ๋ž˜์ผโ‰ˆ1์ผ โ€” ๋‹จ์ผ ์žฅ ๊ณผ์ ํ•ฉ ์œ„ํ—˜ ์ตœ๋Œ€ + - ๊ฑฐ๋ž˜ ํ‘œ๋ณธ: +0.0p โ€” ์ƒ์œ„ ํ›„๋ณด ๊ฑฐ๋ž˜ 16๊ฑด โ€” ์ƒ๋Œ€์  ์–‘ํ˜ธ + - ์Šน๋ฅ ยทPF ์ด์ƒ์น˜: +0.0p โ€” ์ด์ƒ์น˜ ์—†์Œ + - ๊ฒŒ์ดํŠธ ์ปค๋ฒ„: +0.0p โ€” ์‚ฌํ›„ํ•ฉ๊ฒฉ 50๊ฑด ยท stable 10๊ฑด + - PnL ๊ณ ์›: +0.0p โ€” ๊ณ ์› ๋น„์œจ 2% (1๊ฑด) +- ์ž„๊ณ„๊ฐ’ ๋ถ„ํฌ ํ‘œ๋ณธ: results_gated ์ƒ์œ„ 30๊ฑด +| ํŒŒ๋ผ๋ฏธํ„ฐ | median | p25~p75 | mode(๋น„์œจ) | +|---|---:|---|---| +| `entry_mode` | โ€” | โ€” | align (100%) | +| `cand_limit` | 0.0 | 0.0 ~ 0.0 | 0 (77%) | +| `max_daily_change` | 33.0 | 23.25 ~ 40.75 | 43.0 (10%) | +| `min_drop_rate` | 0.055 | 0.025 ~ 0.06 | 0.06 (23%) | +| `min_recovery_ratio` | 0.12 | 0.09 ~ 0.2 | 0.08 (23%) | +| `tail_ratio_min` | 0.9 | 0.7 ~ 1.075 | 1.0 (20%) | +| `tail_pct_min` | 0.00425 | 0.002625 ~ 0.0055 | 0.0025 (13%) | +| `max_rec_3m` | 0.73 | 0.7125 ~ 0.77 | 0.73 (23%) | +| `shoulder_min_high` | 0.011 | 0.00825 ~ 0.01275 | 0.011 (20%) | +| `shoulder_cut_pct` | 0.001 | 0.000625 ~ 0.002 | 0.001 (27%) | +| `stop_atr_mult` | 1.4 | 1.2 ~ 1.7 | 0.9 (17%) | +| `target_atr_mult` | 2.1 | 1.7 ~ 2.5 | 1.7 (20%) | +- _์ฐธ๊ณ : ๊ณผ์ ํ•ฉ%๋Š” ๊ต์ฐจ๊ฒ€์ฆ ์ ์ˆ˜๊ฐ€ ์•„๋‹ˆ๋ผ ํ‘œ๋ณธยท์ด์ƒ์น˜ยท๊ณ ์› ํœด๋ฆฌ์Šคํ‹ฑ์ž…๋‹ˆ๋‹ค. ์ ์šฉ ๊ฐ€๋Šฅ๋„%=100โˆ’๊ณผ์ ํ•ฉ์œ„ํ—˜%. DB ์ ์šฉ ๋ฒ„ํŠผ ํ™œ์„ฑ ์กฐ๊ฑด(gated PnL>0)๊ณผ๋Š” ๋ณ„๊ฐœ์ž…๋‹ˆ๋‹ค._ + +## ์ตœ์ข… ์„ ํƒ ํ›„๋ณด (๊ทœ์น™ ยท DB ์ ์šฉ ์ „ ํ™•์ธ) +- ์•„๋ž˜๋Š” **์—ญํ• ์ด ๋‹ค๋ฅธ** 4์ข… ํ›„๋ณด์ž…๋‹ˆ๋‹ค. mode Top10 1์œ„ โ‰  ์ต์ ˆ ๋Œ€ํ‘œ ยท **DB 1์ˆœ์œ„๋Š” ์‚ฌํ›„ํ•ฉ๊ฒฉ(gated)** ์ž…๋‹ˆ๋‹ค. +- mode pool: `positive` ยท scoring: `band_proximity_p25_p75` + +### ํ›„๋ณด 4์ข… +- **โ‘  ์‚ฌํ›„ํ•ฉ๊ฒฉ 1์œ„ (apply: gated)** (trial #184): PnL 47,512์› ยท WR 68.8% ยท PF 2.76 ยท ๊ฑฐ๋ž˜ 16๊ฑด ยท ์•ˆ์ •์ ์ˆ˜ -1725 ยท ํ˜ธ๊ฐ€ON spr5.9 r0.35 askร—41 ยท ํœฉ์˜OFF +- **โ‘ก ์•ˆ์ • 1์œ„ (apply: stable)** (trial #125): PnL 12,585์› ยท WR 63.6% ยท PF 1.22 ยท ๊ฑฐ๋ž˜ 22๊ฑด ยท ์•ˆ์ •์ ์ˆ˜ 3301 ยท ํ˜ธ๊ฐ€ON spr7.7 r0.85 askร—45 ยท ํœฉ์˜ON sub60s lb90s dip0.80% tol0.30% +- **โ‘ข mode_combo (apply: mode)** (trial ์—†์Œ(์กฐ๋ฆฝ)): PnL 0์› ยท WR 0.0% ยท PF 0.00 ยท ๊ฑฐ๋ž˜ 0๊ฑด ยท ํ˜ธ๊ฐ€ON spr6.5 r0.25 askร—16 ยท ํœฉ์˜OFF +- **โ‘ฃ mode Top10 1์œ„ (apply: consensus ยท ๋ฐด๋“œ ์ „ํ˜• trial)** (trial #84): PnL 14,149์› ยท WR 56.9% ยท PF 1.09 ยท ๊ฑฐ๋ž˜ 58๊ฑด ยท ์•ˆ์ •์ ์ˆ˜ -8818 ยท ๊ทผ์ ‘ 96.8% (44/52์ถ• ๋ฐด๋“œ์•ˆ) ยท ํ˜ธ๊ฐ€ON spr5.0 r0.20 askร—52 ยท ํœฉ์˜OFF +- mode Top10 meta: pool 50๊ฑด ยท ์ถ• 52๊ฐœ + +### ์ถ”์ฒœ (์ž๋™ ยท confirm ํ•„์ˆ˜) +1. **์‹ค๋งค DB ์ ์šฉ 1์ˆœ์œ„ โ†’ โ‘  ์‚ฌํ›„ํ•ฉ๊ฒฉ 1์œ„** (`optunaApply gated`) โ€” WR/PFยทmin_trades ์‚ฌํ›„ ํ†ต๊ณผ. +2. **๋ณ€๋™์„ฑยท์†์‹ค์ผ ์ค„์ด๊ธฐ โ†’ โ‘ก ์•ˆ์ • 1์œ„** (`stable`) โ€” PnL๋ณด๋‹ค ์ผ๋ณ„ ์•ˆ์ • ์šฐ์„  ์‹œ. +3. **2์ฐจ narrowยท๋Œ€ํ‘œ ์ˆซ์ž โ†’ โ‘ข mode_combo** โ€” ์ถ•๋ณ„ ์ตœ๋นˆ ์กฐ๋ฆฝ ยท trial ๋ฒˆํ˜ธ ์—†์Œ ยท ์ต์ ˆ์€ pool ์ตœ๋นˆ๊ฐ’ ์ฐธ๊ณ . +4. **โ‘ฃ mode Top10 1์œ„** โ€” ์–‘์ˆ˜ pool ์ „ํ˜• trial(๋‹ค์ถ• ๋ฐด๋“œ ๊ทผ์ ‘). **์ต์ ˆ ํ•˜๋‚˜๋กœ ์“ฐ์ง€ ๋ง ๊ฒƒ** ยท ํ‘œ์—์„œ ใ€Œ๋ณด๊ธฐใ€โ†’ consensus apply. + +## ์ด์ „ ์žฅ์—์„œ๋Š” +- ์‹ค๋งค ๋™๊ธฐ๊ฐ„ ์ฒญ์‚ฐ 8๊ฑด ยท ์Šน๋ฅ  50% ยท ํ•ฉ์‚ฐ PnL 121,682์› (๋ฐฑํ…Œ Optuna์™€ ์ˆซ์ž ๋‹ฌ๋ผ๋„ ์ •์ƒ โ€” ๊ณ ์ŠคํŠธยท์œ ๋‹ˆ๋ฒ„์Šคยทํ‹ฑ ๊ฒฝ๋กœ ์ฐจ์ด). +- ์‚ฌํ›„ํ•ฉ๊ฒฉ 1์œ„: trial #184 ยท ๊ฑฐ๋ž˜ 16๊ฑด ยท ์Šน๋ฅ  68.8% ยท PF 2.76 ยท PnL 47,512์› +- ํ‘œ๋ณธ ์žฅ์ด 1์ผ๋ฟ์ด๋ผ, โ€˜์ด์ „ ์žฅ์— ์ž˜ ๋จนํžŒ ์ˆซ์žโ€™์ผ ๋ฟ **์ถ”์„ธ๊ฐ€ ๋ฐ”๋€Œ๋ฉด ๋ฐ”๋กœ ๊นจ์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.** + +## ์•ž์œผ๋กœ ์žฅ์—์„œ๋Š” +- **1~2์ผ Optuna best๋ฅผ ๋ฐ”๋กœ ์‹ค๋งค์— ๋„ฃ์ง€ ๋งˆ์„ธ์š”.** ๋‹ค์ผ(โ‰ฅ5๊ฑฐ๋ž˜์ผ) ์žฌ๊ฒ€์ฆยท์›น๋ฐฑํ…Œ 1ํšŒ ํ›„ ๊ฒ€ํ† . +- ์ ์šฉ ์‹œ์—๋Š” `results_gated` ํ›„๋ณด๋งŒ. ํƒ์ƒ‰์šฉ best(objective)์™€ ๋‹ค๋ฅผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. +- ์žฅ์ด ์ข์•„์ง€๊ฑฐ๋‚˜ ๋ณ€๋™์„ฑ์ด ์ปค์ง€๋ฉด: ์†์ ˆยทํŠธ๋ ˆ์ผยท์‹œ๊ฐ„์ฐฝ์ด ๋จผ์ € ๊นจ์ง‘๋‹ˆ๋‹ค. ์Šน๋ฅ  ์ž๋ž‘๋ณด๋‹ค **์†์ ˆ์ด ์‚ด์•„ ์žˆ๋Š”์ง€**๋ฅผ ๋ณด์„ธ์š”. +- ์‚ฌํ›„ํ•ฉ๊ฒฉ์ด ์žˆ์–ด๋„ โ€˜๋‚ด์ผ๋„ ๊ฐ™์€ ์žฅโ€™์ด ์•„๋‹™๋‹ˆ๋‹ค. ํŽ˜์ดํผ/์†Œ์•กยท๋ชจ์˜๋กœ 1~2์ผ ๊ด€์ฐฐ ํ›„ ํ™•๋Œ€ํ•˜์„ธ์š”. + +_์ƒ์„ฑ: 2026-09-05 01:04:14 (rule)_ + +## AI ์ฝ”๋ฉ˜ํŠธ (์ด์ „ ์žฅ / ์•ž์œผ๋กœ ์žฅ) [gemini] + +## ์ด์ „ ์žฅ์—์„œ๋Š” + +์ง€๋‚œ ์žฅ ์‹ค๋งค ๊ฒฐ๊ณผ๋Š” 8๊ฑด ์ฒญ์‚ฐ์— 12๋งŒ1์ฒœ์› ์ˆ˜์ต์ด์—ˆ์œผ๋‚˜, ์ด๋Š” ๋ฐฑํ…Œ์ŠคํŠธ์™€ ๊ดด๋ฆฌ๊ฐ€ ์กด์žฌํ•ฉ๋‹ˆ๋‹ค. Optuna ์‚ฌํ›„ํ•ฉ๊ฒฉ 1์œ„๋Š” 1์ผ๊ฐ„ 16๊ฑด ๊ฑฐ๋ž˜๋กœ PnL 4.7๋งŒ์›์„ ๊ธฐ๋กํ–ˆ์ง€๋งŒ, ๋‹จ์ผ ์žฅ ๊ฒฐ๊ณผ๋Š” ๊ณผ์ ํ•ฉ ์œ„ํ—˜์ด ๋†’์•„ ์ถ”์„ธ๊ฐ€ ๋ฐ”๋€Œ๋ฉด ๋ฐ”๋กœ ๋ฌด๋„ˆ์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. + +## ์•ž์œผ๋กœ ์žฅ์—์„œ๋Š” + +๋‹จ 1์ผ Optuna ๊ฒฐ๊ณผ๋Š” ๊ณผ์ ํ•ฉ ์œ„ํ—˜์ด ๋†’์œผ๋‹ˆ, ์‹ค๋งค ์ „ ๋‹ค์ผ(โ‰ฅ5์ผ) ์žฌ๊ฒ€์ฆ๊ณผ ์›น๋ฐฑํ…Œ์ŠคํŠธ๋ฅผ ๊ถŒํ•ฉ๋‹ˆ๋‹ค. 'mode Top10 1์œ„'๋Š” ์ต์ ˆ ๋Œ€ํ‘œ๊ฐ€ ์•„๋‹Œ ํ›„๋ณด ์ค‘ ํ•˜๋‚˜์ด๋ฉฐ, DB 1์ˆœ์œ„๋Š” ์‚ฌํ›„ํ•ฉ๊ฒฉ์ž…๋‹ˆ๋‹ค. ์‹ค๋งค-๋ฐฑํ…Œ ๊ดด๋ฆฌ(๊ณ ์ŠคํŠธํผ์ง€ ๋“ฑ)๋„ ์œ ์˜ํ•˜์„ธ์š”. ์Šน๋ฅ ๋ณด๋‹ค ์†์ ˆ ์ž‘๋™ ์—ฌ๋ถ€๋ฅผ ํ™•์ธํ•˜๋ฉฐ, ํŽ˜์ดํผ/์†Œ์•ก ๋ชจ์˜ ํ›„ ์‹ ์ค‘ํžˆ ํ™•๋Œ€ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ํŠน์ • ์ข…๋ชฉ ์ถ”์ฒœ ๋ฐ ํ™•์ • ์ˆ˜์ต์€ ๋ถˆ๊ฐ€ํ•ฉ๋‹ˆ๋‹ค. diff --git a/kis_trader/backtest/scalping_backtest_common.py b/kis_trader/backtest/scalping_backtest_common.py index 2452eda..d9af9fc 100644 --- a/kis_trader/backtest/scalping_backtest_common.py +++ b/kis_trader/backtest/scalping_backtest_common.py @@ -21,7 +21,7 @@ from kis_trader.backtest.backtest_portfolio_common import ( summarize_trades, ) from kis_trader.backtest.breakout_tick_loader import ( - load_breakout_ticks_by_code, + load_common_ticks_by_code, tick_coverage_stats, ) from kis_trader.engine import scalping_engine as se @@ -288,8 +288,9 @@ def run_scalping_backtest_web_aligned( ) _tick_tbl = "ls_ws_ticks" else: - loaded_ticks, tick_rows = load_breakout_ticks_by_code( + loaded_ticks, tick_rows = load_common_ticks_by_code( db, start_key, end_key, set(candles_by_code.keys()), + use_spill_fallback=(str(engine_params.get("backtest_use_spill_fallback", True)).lower() in ("1", "true", "t", "y", "yes", "on")), ) _tick_tbl = "ws_ticks" tick_meta = tick_coverage_stats(candles_by_code, loaded_ticks) @@ -304,7 +305,12 @@ def run_scalping_backtest_web_aligned( _tick_tbl, ) elif loaded_ticks: - tick_meta = tick_coverage_stats(candles_by_code, loaded_ticks) + if "_tick_meta_cached" in engine_params: + tick_meta = dict(engine_params["_tick_meta_cached"]) + else: + tick_meta = tick_coverage_stats(candles_by_code, loaded_ticks) + engine_params["_tick_meta_cached"] = tick_meta + tick_meta["ws_tick_rows_loaded"] = sum( len(lst) for cm in loaded_ticks.values() for lst in cm.values() ) @@ -325,10 +331,70 @@ def run_scalping_backtest_web_aligned( if pg_loaded is not None: engine_params["_bt_program_by_code"] = pg_loaded - trades = se.run_scalping_backtest( - candles_by_code, engine_params, universe_by_slot=universe_by_slot, - ticks_by_code=loaded_ticks or None, - ) + rust_session = engine_params.get("_rust_session_id") + if rust_session: + try: + import kis_rust_core + p = engine_params + def get_float(k, default=0.0): + try: return float(p.get(k, default)) + except: return float(default) + def get_int(k, default=0): + try: return int(p.get(k, default)) + except: return int(default) + def get_bool(k, default=False): + v = p.get(k, default) + if isinstance(v, bool): return v + s = str(v).lower() + if s in ("1", "true", "yes", "t", "y"): return True + return False + + sp = kis_rust_core.ScalpParams( + get_int("rsi_period", 14), + get_float("rsi_oversold", 30.0), + get_float("rsi_overbought", 70.0), + abs(get_float("sl_pct", 0.02)), + get_float("tp_pct", 0.05), + get_float("drop_rate", 0.0), + get_float("cooldown_min", 0.0), + get_int("max_daily", 10), + get_float("high_chase_thr", 1.2), + get_float("max_daily_chg", 25.0), + get_float("min_price", 1000.0), + get_float("vol_mult", 0.0), + get_bool("use_defense_filters", False), + get_bool("skip_hts", False), + get_int("time_start_hm", 900), + get_int("time_end_hm", 1520), + ) + r_trades = kis_rust_core.run_engine_trial_scalp(rust_session, sp) + trades = [ + { + "code": rt.code, + "entry_time": rt.buy_time, + "exit_time": rt.sell_time, + "entry": rt.buy_price, + "exit": rt.sell_price, + "pnl": 0, + "pnl_pct": rt.pnl_pct, + "reason": rt.reason, + "peak_price": rt.sell_price, # ๊ฐ„์†Œํ™” + "rsi": rt.rsi_entry, + "qty": None, + "entry_source": "rust_engine", + "ob_source": "", + "hold_min": 0, + } + for rt in r_trades + ] + except Exception as e: + print(f"[ERROR] Rust run_engine_trial_scalp failed: {e}") + trades = [] + else: + trades = se.run_scalping_backtest( + candles_by_code, engine_params, universe_by_slot=universe_by_slot, + ticks_by_code=loaded_ticks or None, + ) if meta_out is not None and tick_meta: from kis_trader.backtest.breakout_tick_loader import enrich_tick_meta_with_traded_codes tick_meta = enrich_tick_meta_with_traded_codes( @@ -347,6 +413,16 @@ def run_scalping_backtest_web_aligned( if snap_meta: meta_out["trigger_snapshot_backtest"] = snap_meta + try: + from kis_trader.backtest.bt_post_filters import apply_bt_post_filters + trades = apply_bt_post_filters( + trades, + engine_params, + strategy="SCALP" + ) + except Exception as e: + print(f"[ERROR] bt_post_filters failed: {e}") + attach_scalp_trade_pnl( trades, fee_rate=fee_rate, sell_tax=sell_tax, slip_pct=backtest_slip_pct(engine_params), diff --git a/kis_trader/backtest/tail_backtest_common.py b/kis_trader/backtest/tail_backtest_common.py index ea2fbe4..56a89d0 100644 --- a/kis_trader/backtest/tail_backtest_common.py +++ b/kis_trader/backtest/tail_backtest_common.py @@ -684,46 +684,47 @@ def run_tail_backtest_web_aligned( # 1๋ถ„ ์Šฌ๋กฏ(strict lag)์˜ "ํŽธ์ž… +์ตœ๋Œ€ 1๋ถ„ ์ง€์—ฐ" ์„ ์ œ๊ฑฐ. ๋ด‰ ๋งˆ๊ฐ(HH:MM:59) ์ง์ „ # ์ตœ์‹  ์กฐ๊ฑด๊ฒ€์ƒ‰ ์Šค๋ƒ…์ƒท์„ ๊ทธ๋Œ€๋กœ ์กฐํšŒํ•ด ์‹ค๋งค์™€ ๋™์ผ ์‹œ์  ์œ ๋‹ˆ๋ฒ„์Šค๋กœ ๋งค์ˆ˜ ํŒ์ •. if universe_by_slot is not None and tail_backtest_universe_scan_at_enabled(engine_params): - _sk = str((meta_out or {}).get("start_key") or "") - _ek = str((meta_out or {}).get("end_key") or "") - if len(_sk) < 8 or len(_ek) < 8: - # meta_out ํ‚ค ์—†์œผ๋ฉด ์บ”๋“ค ์‹œ๊ฐ min/max ์ผ์ž๋กœ ํด๋ฐฑ - _days = [ - str(c.get("candle_time") or "")[:8] - for rows in candles_by_code.values() for c in rows - if c.get("candle_time") - ] - if _days: - _sk, _ek = min(_days), max(_days) - if len(_sk) >= 8 and len(_ek) >= 8: - from kis_trader.backtest.universe_timeline import ( - build_universe_timeline, - universe_exit_debounce_sec_for_strategy, - ) - from kis_trader.backtest.universe_history_source import ( - resolve_backtest_universe_history_source, - ) + if "_universe_timeline" not in engine_params: + _sk = str((meta_out or {}).get("start_key") or "") + _ek = str((meta_out or {}).get("end_key") or "") + if len(_sk) < 8 or len(_ek) < 8: + # meta_out ํ‚ค ์—†์œผ๋ฉด ์บ”๋“ค ์‹œ๊ฐ min/max ์ผ์ž๋กœ ํด๋ฐฑ + _days = [ + str(c.get("candle_time") or "")[:8] + for rows in candles_by_code.values() for c in rows + if c.get("candle_time") + ] + if _days: + _sk, _ek = min(_days), max(_days) + if len(_sk) >= 8 and len(_ek) >= 8: + from kis_trader.backtest.universe_timeline import ( + build_universe_timeline, + universe_exit_debounce_sec_for_strategy, + ) + from kis_trader.backtest.universe_history_source import ( + resolve_backtest_universe_history_source, + ) - _deb = universe_exit_debounce_sec_for_strategy(TAIL_STRATEGY_ID) - # ์Šฌ๋กฏ dict(resolve_tail_universe)์™€ ๋™์ผ ์†Œ์Šค โ€” LS ๋ผ๋ฒจ์ธ๋ฐ ํ‚ค์›€ ํƒ€์ž„๋ผ์ธ ์“ฐ๋Š” ์‚ฌ๊ณ  ๋ฐฉ์ง€ - _hs = resolve_backtest_universe_history_source( - engine_params.get("_universe_history_source") - or engine_params.get("universe_history_source") - ) - engine_params["_universe_history_source"] = _hs - _tl = build_universe_timeline( - strategy_id=TAIL_STRATEGY_ID, - start_ymd=_sk[:8], end_ymd=_ek[:8], - debounce_sec=_deb, strict=False, strict_lag_minutes=0, - history_source=_hs, - ) - if _tl is not None: - engine_params["_universe_timeline"] = _tl - if meta_out is not None: - meta_out["universe_timing"] = "scan_at" - meta_out["universe_timeline_snapshots"] = _tl.snapshot_count - meta_out["universe_exit_debounce_sec"] = _deb - meta_out["universe_history_source"] = _hs + _deb = universe_exit_debounce_sec_for_strategy(TAIL_STRATEGY_ID) + # ์Šฌ๋กฏ dict(resolve_tail_universe)์™€ ๋™์ผ ์†Œ์Šค โ€” LS ๋ผ๋ฒจ์ธ๋ฐ ํ‚ค์›€ ํƒ€์ž„๋ผ์ธ ์“ฐ๋Š” ์‚ฌ๊ณ  ๋ฐฉ์ง€ + _hs = resolve_backtest_universe_history_source( + engine_params.get("_universe_history_source") + or engine_params.get("universe_history_source") + ) + engine_params["_universe_history_source"] = _hs + _tl = build_universe_timeline( + strategy_id=TAIL_STRATEGY_ID, + start_ymd=_sk[:8], end_ymd=_ek[:8], + debounce_sec=_deb, strict=False, strict_lag_minutes=0, + history_source=_hs, + ) + if _tl is not None: + engine_params["_universe_timeline"] = _tl + if meta_out is not None: + meta_out["universe_timing"] = "scan_at" + meta_out["universe_timeline_snapshots"] = _tl.snapshot_count + meta_out["universe_exit_debounce_sec"] = _deb + meta_out["universe_history_source"] = _hs # โ”€โ”€ ์ฒด๊ฒฐ ๊ฒ€์ฆ ๊ฒŒ์ดํŠธ (STRICT_FILL_VERIFY) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ # ๋ฐฑํ…Œ ์ฒด๊ฒฐ๋ชจ๋ธ(์Šฌ๋ฆฌํ”ผ์ง€ยท์ฒด๊ฒฐ๋Ÿ‰ ์ƒํ•œ)์€ '์—„๊ฒฉ ์ฒด๊ฒฐ ๊ฒ€์ฆ'์ด ์ผœ์กŒ์„ ๋•Œ๋งŒ ์ ์šฉํ•œ๋‹ค. @@ -780,20 +781,106 @@ def run_tail_backtest_web_aligned( if snap_meta.get("log_verdict_by_code"): engine_params["_backtest_log_verdict_by_code"] = snap_meta["log_verdict_by_code"] - trades = te.run_tail_backtest( - candles_by_code, - engine_params, - universe_by_slot=universe_by_slot, - ticks_by_code=loaded_ticks or None, - orderbook_by_code=ob_loaded, - program_by_code=pg_loaded, - ) + rust_session = engine_params.get("_rust_session_id") + if rust_session: + import kis_rust_core + # ๋”•์…”๋„ˆ๋ฆฌ์—์„œ ํŒŒ๋ผ๋ฏธํ„ฐ ์ถ”์ถœ (์—†์œผ๋ฉด 0 ๋˜๋Š” ๊ธฐ๋ณธ๊ฐ’) + p = engine_params + def get_float(k, default=0.0): + try: return float(p.get(k, default)) + except: return float(default) + + def get_int(k, default=0): + try: return int(p.get(k, default)) + except: return int(default) + + def get_bool(k, default=False): + v = p.get(k, default) + if isinstance(v, bool): return v + s = str(v).lower() + if s in ("1", "true", "yes", "t", "y"): return True + return False + + tp = kis_rust_core.TailParams( + get_int("time_start_hm", 930), + get_int("time_end_hm", 1500), + get_float("cooldown_min", 15.0), + get_int("max_daily", 3), + get_float("min_price", 1000.0), + get_float("rsi_threshold", 78.0), + get_float("min_drop_rate", 0.03), + get_float("min_recovery_ratio", 0.5), + get_float("tail_pct_min", 0.003), + get_float("tail_ratio_min", 1.5), + get_bool("pattern_hammer", True), + get_bool("pattern_pin", False), + get_bool("pattern_engulfing", False), + get_bool("pattern_piercing", False), + get_bool("pattern_harami", False), + get_bool("pattern_doji", False), + get_bool("pattern_morning_star", False), + get_bool("skip_hts_scan_dupes", True), + abs(get_float("sl_pct", 0.03)), + get_float("tp_pct", 0.05), + get_float("trail_pct", 0.0), + get_float("trail_arm_pct", 0.0), + get_float("shoulder_min_high", 0.005), + get_float("shoulder_cut_pct", 0.003), + get_int("max_hold_bars", 0), + get_float("max_loss_krw", 200000.0), + get_float("min_drop_pct_for_loss_cut", 0.015), + ) + try: + r_trades = kis_rust_core.run_engine_trial_tail(rust_session, tp) + # ํŒŒ์ด์ฌ ๋”•์…”๋„ˆ๋ฆฌ ๋ฆฌ์ŠคํŠธ๋กœ ๋งคํ•‘ + trades = [ + { + "code": rt.code, + "entry_time": rt.buy_time, + "exit_time": rt.sell_time, + "entry": rt.buy_price, + "exit": rt.sell_price, + "pnl": 0, + "pnl_pct": rt.pnl_pct, + "reason": rt.reason, + "peak_price": rt.max_price, + "rsi": rt.rsi_entry, + "qty": None, + "entry_source": "rust_engine", + "ob_source": "", + "hold_min": 0, + } + for rt in r_trades + ] + except Exception as e: + print(f"[ERROR] Rust run_engine_trial_tail failed: {e}") + trades = [] + else: + trades = te.run_tail_backtest( + candles_by_code, + engine_params, + universe_by_slot=universe_by_slot, + ticks_by_code=loaded_ticks or None, + orderbook_by_code=ob_loaded, + program_by_code=pg_loaded, + ) # ๋ฐฑํ…Œ ์Šฌ๋ฆฌํ”ผ์ง€(ํŽธ๋„ %) โ€” BACKTEST_SLIP_PCT ๊ณตํ†ตํ‚ค(์ „ ์ „๋žต ๋™์ผ, STRICT ๊ฒŒ์ดํŠธ๋Š” # ํ—ฌํผ๊ฐ€ ์ฒ˜๋ฆฌ). align ์€ ์ง„์ž…+์ฒญ์‚ฐ ์–‘์ธก ๋ฐ˜์˜, limit_atr ์ง„์ž…์€ try_limit_fill_on_bar # ์˜ limit_fill_slip_pct ๋กœ ์ด๋ฏธ ๋ฐ˜์˜๋ผ ์ฒญ์‚ฐ๋งŒ ์ถ”๊ฐ€(entry_already_slipped ๋กœ ์ค‘๋ณต ์ฐจ๋‹จ). from kis_trader.backtest.backtest_portfolio_common import backtest_slip_pct _slip_pct = backtest_slip_pct(engine_params) _entry_mode = str(engine_params.get("entry_mode") or "align").strip().lower() + + try: + from kis_trader.backtest.bt_post_filters import apply_bt_post_filters + trades = apply_bt_post_filters( + trades, + engine_params, + strategy="TAIL" + ) + except Exception as e: + print(f"[ERROR] bt_post_filters failed: {e}") + attach_tail_trade_pnl( trades, slot_money=slot_money, fee_rate=fee_rate, sell_tax=sell_tax, slip_pct=_slip_pct, diff --git a/kis_trader/backtest/tail_param_search.py b/kis_trader/backtest/tail_param_search.py index 30e3d1b..981deb9 100644 --- a/kis_trader/backtest/tail_param_search.py +++ b/kis_trader/backtest/tail_param_search.py @@ -1005,7 +1005,7 @@ TAIL_GRID_AXIS_HINTS_KO: Dict[str, str] = { "max_daily_change": "๊ธ‰๋“ฑ์ฃผ ํ•„ํ„ฐ(๋‹น์ผ ๋“ฑ๋ฝ๋ฅ  ์ƒํ•œ, %)", "trail_pct": "๋ณด์กฐ ํŠธ๋ ˆ์ผ ํญ(๊ณ ์  ๋Œ€๋น„, 0=OFF). ๋ž˜์นซ ON์ด๋ฉด 1๋‹จ๊ณ„๋ณด๋‹ค arm์ด ์ปค์•ผ ํšจ๊ณผ", "trail_arm_pct": "๋ณด์กฐ ํŠธ๋ ˆ์ผ ๋ฌด์žฅ: ์ง„์ž…ร—(1+arm) ๋„๋‹ฌ ํ›„ (0=์ฆ‰์‹œ)", - "whipsaw_enabled": "ํœฉ์˜ ํ•„ํ„ฐ ON/OFF โ€” ์‹ค๋งค TAIL_WHIPSAW_FILTER_ENABLED (ํ˜„์žฌ false ํฌํ•จ)", + "whipsaw_filter_enabled": "ํœฉ์˜ ํ•„ํ„ฐ ON/OFF โ€” ์‹ค๋งค TAIL_WHIPSAW_FILTER_ENABLED (ํ˜„์žฌ false ํฌํ•จ)", "whipsaw_subbar_sec": "ํœฉ์˜ ๋ฏธ๋‹ˆ๋ด‰(์ดˆ) โ€” ๊ธฐ๋ณธ 30 ยท TPE [15,30,45,60]", "whipsaw_lookback_sec": "ํœฉ์˜ ๋ฃฉ๋ฐฑ(์ดˆ) โ€” ๊ธฐ๋ณธ 90 ยท TPE [60,90,120,180]", "whipsaw_dip_pct": "ํœฉ์˜ ์ง€์ง€์ดํƒˆ ํ•˜๋ฝํญ(๋ถ„์œจ) โ€” ๊ธฐ๋ณธ 0.003", @@ -1332,6 +1332,7 @@ def run_search( if tick_rows > 0: tick_backtest_meta = tick_coverage_stats(candles_by_code, ticks_by_code) tick_backtest_meta["ws_tick_rows_loaded"] = tick_rows + base_params["_tick_meta_cached"] = tick_backtest_meta cov = tick_backtest_meta.get("tick_bar_coverage_pct", 0) logger.info( "โœ… ws_ticks %s๊ฑด | 3๋ถ„๋ด‰ ์ปค๋ฒ„๋ฆฌ์ง€ %s%% (%s/%s์ข…๋ชฉ)", diff --git a/kis_trader/backtest/tail_tick_loader.py b/kis_trader/backtest/tail_tick_loader.py index 984726a..51b3341 100644 --- a/kis_trader/backtest/tail_tick_loader.py +++ b/kis_trader/backtest/tail_tick_loader.py @@ -4,15 +4,15 @@ from __future__ import annotations from kis_trader.backtest.breakout_tick_loader import ( enrich_tick_meta_with_traded_codes, - load_breakout_ticks_by_code, + load_common_ticks_by_code, tick_coverage_stats, ) __all__ = [ "enrich_tick_meta_with_traded_codes", - "load_breakout_ticks_by_code", + "load_common_ticks_by_code", "load_tail_ticks_by_code", "tick_coverage_stats", ] -load_tail_ticks_by_code = load_breakout_ticks_by_code +load_tail_ticks_by_code = load_common_ticks_by_code diff --git a/kis_trader/database/db_manager.py b/kis_trader/database/db_manager.py index 0501fd2..4fb7e06 100644 --- a/kis_trader/database/db_manager.py +++ b/kis_trader/database/db_manager.py @@ -98,6 +98,8 @@ class TradeDBExt: filled_at VARCHAR(30) DEFAULT NULL, raw_json MEDIUMTEXT DEFAULT NULL, is_mock TINYINT(1) NULL, + target_price DOUBLE DEFAULT NULL, + slippage_pct DOUBLE DEFAULT NULL, PRIMARY KEY (id), UNIQUE KEY uq_ord_no_ctx (ord_no, strategy_id, code, side, ord_date, is_mock), INDEX idx_strategy_date (strategy_id, ord_date), @@ -109,6 +111,7 @@ class TradeDBExt: self._migrate_orders_pk_scope() self._migrate_orders_is_mock() self._migrate_orders_broker_debug_columns() + self._migrate_orders_slippage_columns() logger.info("๐Ÿ“Š orders ํ…Œ์ด๋ธ” ํ™•์ธ/์ƒ์„ฑ ์™„๋ฃŒ") except Exception as e: logger.warning("orders ํ…Œ์ด๋ธ” ์ƒ์„ฑ ์‹คํŒจ(๋ฌด์‹œยทํด๋ฐฑ): %s", e) @@ -248,6 +251,23 @@ class TradeDBExt: except Exception as e: logger.warning("orders broker debug ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ์‹คํŒจ(๋ฌด์‹œยทํด๋ฐฑ): %s", e) + def _migrate_orders_slippage_columns(self) -> None: + """orders โ€” ์‹ค๋งค๋งค vs ๋ฐฑํ…Œ์ŠคํŠธ ์Šฌ๋ฆฌํ”ผ์ง€ ๊ฐญ ๋ชจ๋‹ˆํ„ฐ๋ง์šฉ ์ปฌ๋Ÿผ.""" + specs = { + "target_price": "DOUBLE NULL", + "slippage_pct": "DOUBLE NULL", + } + try: + cols = self.conn.get_columns("orders") + for col, ddl in specs.items(): + if col not in cols: + self.conn.execute( + f"ALTER TABLE orders ADD COLUMN `{col}` {ddl}" + ) + logger.info("๐Ÿ“Œ orders.%s ์ปฌ๋Ÿผ ์ถ”๊ฐ€ (์Šฌ๋ฆฌํ”ผ์ง€ ๋ชจ๋‹ˆํ„ฐ๋ง)", col) + except Exception as e: + logger.warning("orders slippage ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ์‹คํŒจ(๋ฌด์‹œยทํด๋ฐฑ): %s", e) + # ------------------------------------------------------------------ # orders CRUD # ------------------------------------------------------------------ @@ -266,6 +286,7 @@ class TradeDBExt: msg1: Optional[str] = None, raw_json: Optional[str] = None, is_mock=None, + target_price: Optional[float] = None, ) -> bool: """ ์ฃผ๋ฌธ ๊ธฐ๋ก INSERT. @@ -283,8 +304,8 @@ class TradeDBExt: """ INSERT INTO orders ( ord_no, strategy_id, code, name, side, qty, price, - status, msg_cd, msg1, ord_date, submitted_at, raw_json, is_mock - ) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s) + status, msg_cd, msg1, ord_date, submitted_at, raw_json, is_mock, target_price + ) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s) """, ( ord_no, strategy_id, code, name, side, qty, price, @@ -293,6 +314,7 @@ class TradeDBExt: now.strftime("%Y-%m-%d %H:%M:%S"), raw_json, mock_flag, + target_price, ), ) return True @@ -334,11 +356,15 @@ class TradeDBExt: self.conn.execute( """ UPDATE orders - SET filled_qty=%s, filled_avg_price=%s, status=%s, filled_at=%s + SET filled_qty=%s, + filled_avg_price=%s, + slippage_pct=IF(target_price IS NOT NULL AND target_price > 0, ((%s - target_price) / target_price) * 100, slippage_pct), + status=%s, + filled_at=%s WHERE ord_no=%s AND strategy_id=%s AND code=%s AND ord_date=%s AND is_mock=%s """, - (filled_qty, filled_avg_price, status, now, + (filled_qty, filled_avg_price, filled_avg_price, status, now, ord_no, strategy_id, code, od, mock_flag), ) return True diff --git a/kis_trader/engine/breakout_engine.py b/kis_trader/engine/breakout_engine.py index 2a39695..2bb1d49 100644 --- a/kis_trader/engine/breakout_engine.py +++ b/kis_trader/engine/breakout_engine.py @@ -88,6 +88,11 @@ def run_breakout_backtest_rust_experimental( "sell_time": t.sell_time, "buy_price": t.buy_price, "sell_price": t.sell_price, + "entry_time": t.buy_time, + "exit_time": t.sell_time, + "entry": t.buy_price, + "exit": t.sell_price, + "exit_reason": t.reason, "profit_rate": t.pnl_pct, "sell_reason": t.reason, "qty": 1, # ๋‹จ์ˆœํ™”๋ฅผ ์œ„ํ•ด 1๋กœ ๊ณ ์ •, ์ถ”ํ›„ ์˜ˆ์‚ฐ ๋กœ์ง ๋ฐ˜์˜ ๊ฐ€๋Šฅ diff --git a/kis_trader/engine/feed_fallback.py b/kis_trader/engine/feed_fallback.py index 08e5b62..9cc440e 100644 --- a/kis_trader/engine/feed_fallback.py +++ b/kis_trader/engine/feed_fallback.py @@ -452,10 +452,14 @@ def orderbook_row_lag_seconds(row: Dict[str, Any]) -> Optional[int]: def candle_garbage_fallback_enabled() -> bool: + import os + if os.environ.get("BACKTEST_CANDLE_GARBAGE_OFF") == "1": + return False + # ์‚ฌ์šฉ์ž ์ง€์‹œ(์“ฐ๋ ˆ๊ธฐ์Šคํ‚ต ์ „๋ฉด ํ์ง€)์— ๋”ฐ๋ผ ๊ธฐ๋ณธ๊ฐ’์„ False๋กœ ๋ณ€๊ฒฝ try: - return bool(get_env_bool("CANDLE_GARBAGE_FALLBACK", True)) + return bool(get_env_bool("CANDLE_GARBAGE_FALLBACK", False)) except Exception: - return True + return False def bar_end_datetime(candle_time: str, tf_min: int): diff --git a/kis_trader/engine/momentum_engine.py b/kis_trader/engine/momentum_engine.py index 5ef29c7..0eed820 100644 --- a/kis_trader/engine/momentum_engine.py +++ b/kis_trader/engine/momentum_engine.py @@ -92,6 +92,113 @@ def effective_tp_pct_from_params(params: Dict[str, Any]) -> float: ) +import os + +try: + import kis_rust_core +except ImportError: + kis_rust_core = None + +def run_momentum_backtest_rust_experimental( + codes_candles: Dict[str, List[Dict]], + params: Dict[str, Any] +) -> List[Dict]: + """๋ชจ๋ฉ˜ํ…€ ๋งค๋งค Rust ์—”์ง„ ์‹คํ—˜์šฉ ๋ธŒ๋ฆฟ์ง€""" + if kis_rust_core is None: + raise RuntimeError("kis_rust_core module is not available") + + def get_float(k, default=0.0): + try: return float(params.get(k, default)) + except: return float(default) + + def get_int(k, default=0): + try: return int(params.get(k, default)) + except: return int(default) + + def get_bool(k, default=False): + v = params.get(k, default) + if isinstance(v, bool): return v + s = str(v).lower() + if s in ("1", "true", "yes", "t", "y"): return True + return False + + rust_params = kis_rust_core.MomentumParams( + get_int("time_start_hm", 900), + get_int("time_end_hm", 1530), + get_float("cooldown_min", 10.0), + get_int("max_daily", 5), + get_float("min_price", 1000.0), + get_bool("use_defense_filters", True), + get_bool("use_high_chase_filter", False), + get_float("high_chase_thr", 0.96), + get_bool("trigger_e_confirm", True), + get_bool("trigger_require_bull_bar", True), + get_bool("use_vol_trigger", True), + get_bool("use_rsi_filter", False), + get_bool("use_rsi_max_filter", False), + get_int("rsi_period", 3), + get_float("mom_rsi_min", 50.0), + get_float("mom_rsi_max", 80.0), + get_bool("use_ema_filter", False), + get_int("ema_fast_period", 9), + get_int("ema_slow_period", 21), + get_float("e_min_chg_pct", 0.0), + get_float("mom_vol_mult", 1.2), + get_int("mom_vol_win", 5), + get_bool("skip_hts_scan_dupes", False), + get_float("sl_pct", 0.03), + get_float("tp_pct", 0.08), + get_float("trail_pct", 0.02), + get_float("trail_arm_pct", 0.01), + get_float("shoulder_min_high", 0.005), + get_float("shoulder_cut_pct", 0.003), + get_int("max_hold_bars", 0), + get_float("max_loss_krw", 200000.0), + get_float("min_hold_sec", 30.0), + get_float("min_drop_pct_for_loss_cut", 0.015), + ) + + all_trades = [] + + for code, candles_dict in codes_candles.items(): + rust_candles = [] + for c in candles_dict: + rc = kis_rust_core.CandleData( + c.get("candle_time", ""), + float(c.get("open", 0)), + float(c.get("high", 0)), + float(c.get("low", 0)), + float(c.get("close", 0)), + float(c.get("volume", 0)), + float(c.get("rsi", 0.0)), + ) + rust_candles.append(rc) + + trades = kis_rust_core.run_momentum_backtest_fast(code, rust_candles, rust_params) + for t in trades: + all_trades.append({ + "code": t.code, + "buy_time": t.buy_time, + "sell_time": t.sell_time, + "buy_price": t.buy_price, + "sell_price": t.sell_price, + "entry_time": t.buy_time, + "exit_time": t.sell_time, + "entry": t.buy_price, + "exit": t.sell_price, + "exit_reason": t.reason, + "profit_rate": t.pnl_pct, + "qty": 1, + "pnl": 0, + "sell_reason": t.reason, + "max_price": t.max_price, + "rsi_entry": t.rsi_entry, + "strategy": "MOMENTUM" + }) + + return all_trades + + def get_momentum_defaults_from_db(db=None, *, env_row: Optional[Dict[str, Any]] = None) -> Dict[str, Any]: """env_config + config_momentum ๋ณ‘ํ•ฉ โ†’ ์—”์ง„ params dict.""" own_db = None @@ -583,6 +690,9 @@ def run_momentum_backtest( program_by_code: Optional[Dict[str, Dict[str, List[Any]]]] = None, ) -> List[Dict]: """๋ชจ๋ฉ˜ํ…€ ๋ฐฑํ…Œ์ŠคํŠธ โ€” portfolio_mode ์‹œ ํฌํŠธํด๋ฆฌ์˜ค ๋ชจ๋“ˆ ์œ„์ž„.""" + if params.get("use_rust", False): + return run_momentum_backtest_rust_experimental(codes_candles, params) + if _to_bool(params.get("portfolio_mode"), True): from kis_trader.backtest.momentum_portfolio_backtest import run_momentum_backtest_portfolio return run_momentum_backtest_portfolio( diff --git a/kis_trader/engine/scalping_engine.py b/kis_trader/engine/scalping_engine.py index ce40d2e..33d7c18 100644 --- a/kis_trader/engine/scalping_engine.py +++ b/kis_trader/engine/scalping_engine.py @@ -1431,6 +1431,11 @@ def run_scalping_backtest_rust_experimental( "sell_time": t.sell_time, "buy_price": t.buy_price, "sell_price": t.sell_price, + "entry_time": t.buy_time, + "exit_time": t.sell_time, + "entry": t.buy_price, + "exit": t.sell_price, + "exit_reason": t.reason, "qty": 1, # ์ž„์‹œ "pnl": 0, # PnL ๋ถ€์ฐฉ๋ถ€์—์„œ ์žฌ๊ณ„์‚ฐ "profit_rate": round(t.pnl_pct, 2), diff --git a/kis_trader/engine/tail_engine.py b/kis_trader/engine/tail_engine.py index ecd4568..51c8d38 100644 --- a/kis_trader/engine/tail_engine.py +++ b/kis_trader/engine/tail_engine.py @@ -2566,30 +2566,33 @@ def run_tail_backtest_rust_experimental( get_float("min_drop_pct_for_loss_cut", 0.015), ) - all_trades = [] + import uuid + import json - for code, candles_dict in codes_candles.items(): - rust_candles = [] - for c in candles_dict: - rc = kis_rust_core.CandleData( - c.get("candle_time", ""), - float(c.get("open", 0)), - float(c.get("high", 0)), - float(c.get("low", 0)), - float(c.get("close", 0)), - float(c.get("volume", 0)), - float(c.get("rsi", 0.0)), - ) - rust_candles.append(rc) - - trades = kis_rust_core.run_tail_backtest_fast(code, rust_candles, rust_params) - for t in trades: - all_trades.append({ + session_id = f"exp_tail_{uuid.uuid4().hex[:8]}" + + try: + candles_json = json.dumps(codes_candles) + kis_rust_core.init_backtest_session_json(session_id, candles_json) + except Exception as e: + print(f"[ERROR] Failed to serialize or init rust session: {e}") + return [] + + all_trades = [] + try: + r_trades = kis_rust_core.run_engine_trial_tail(session_id, rust_params) + all_trades = [ + { "code": t.code, "buy_time": t.buy_time, "sell_time": t.sell_time, "buy_price": t.buy_price, "sell_price": t.sell_price, + "entry_time": t.buy_time, + "exit_time": t.sell_time, + "entry": t.buy_price, + "exit": t.sell_price, + "exit_reason": t.reason, "profit_rate": t.pnl_pct, "qty": 1, "pnl": 0, @@ -2597,7 +2600,16 @@ def run_tail_backtest_rust_experimental( "max_price": t.max_price, "rsi_entry": t.rsi_entry, "strategy": "SHORT" - }) + } + for t in r_trades + ] + except Exception as e: + print(f"[ERROR] run_tail_backtest_rust_experimental failed: {e}") + finally: + try: + kis_rust_core.clear_backtest_session(session_id) + except: + pass return all_trades @@ -2915,4 +2927,46 @@ def run_tail_backtest( i += 1 continue - return all_trades \ No newline at end of file + return all_trades +def init_rust_session( + session_id: str, + candles_by_code: Dict[str, List[Dict]], + ticks_by_code: Optional[Dict[str, List[Dict]]] = None, +): + """ + Rust ์ธ๋ฉ”๋ชจ๋ฆฌ ์—”์ง„์— ํŒŒ์ด์ฌ ๋”•์…”๋„ˆ๋ฆฌ ๋ฐ์ดํ„ฐ๋ฅผ ํ•œ ๋ฒˆ์— ๋ฐ€์–ด๋„ฃ๋Š” ๋ž˜ํผ ํ•จ์ˆ˜. + """ + try: + import kis_rust_core + except ImportError: + print("[WARNING] kis_rust_core ๋ชจ๋“ˆ์„ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. Rust ๋ฐฑํ…Œ์ŠคํŠธ๊ฐ€ ๋ถˆ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.") + return + + import json + + # ๋”•์…”๋„ˆ๋ฆฌ๋ฅผ JSON ๋ฌธ์ž์—ด๋กœ ์ง๋ ฌํ™”ํ•˜์—ฌ Rust๋กœ ํ•œ ๋ฒˆ์— ์ „๋‹ฌ (Zero-copy ํŒŒ์‹ฑ) + try: + candles_json = json.dumps(candles_by_code) + except Exception as e: + print(f"[ERROR] Failed to serialize candles to JSON: {e}") + return + + rust_ticks = {} + # Phase 2 ํ‹ฑ ๋ฐ์ดํ„ฐ ์ง€์› ํ™•์žฅ ๋Œ€๋น„ (ํ˜„์žฌ๋Š” ๋นˆ ๋”•์…”๋„ˆ๋ฆฌ ์ „๋‹ฌ) + if ticks_by_code: + pass + + try: + kis_rust_core.init_backtest_session_json(session_id, candles_json) + except Exception as e: + print(f"[ERROR] Failed to init_rust_session: {e}") + +def clear_rust_session(session_id: str): + """ + Rust ์ธ๋ฉ”๋ชจ๋ฆฌ ์—”์ง„์˜ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ํ•ด์ œํ•˜๋Š” ๋ž˜ํผ ํ•จ์ˆ˜. + """ + try: + import kis_rust_core + kis_rust_core.clear_backtest_session(session_id) + except Exception as e: + pass diff --git a/kis_trader/engine/tail_env_keys.py b/kis_trader/engine/tail_env_keys.py index 7c87356..2c6df8b 100644 --- a/kis_trader/engine/tail_env_keys.py +++ b/kis_trader/engine/tail_env_keys.py @@ -322,8 +322,8 @@ def params_to_tail_env_patch(p: Dict[str, Any]) -> Dict[str, str]: if js_k in p and p[js_k] is not None: _set(env_k, p[js_k]) # ํœฉ์˜ TRIGGER (Optuna TPE / apply-best) โ€” ์ „๋žต ์ „์šฉ TAIL_WHIPSAW_* - if "whipsaw_enabled" in p: - _set("TAIL_WHIPSAW_FILTER_ENABLED", str(p["whipsaw_enabled"]).lower()) + if "whipsaw_filter_enabled" in p: + _set("TAIL_WHIPSAW_FILTER_ENABLED", str(p["whipsaw_filter_enabled"]).lower()) for js_k, env_k in ( ("whipsaw_subbar_sec", "TAIL_WHIPSAW_SUBBAR_SEC"), ("whipsaw_lookback_sec", "TAIL_WHIPSAW_LOOKBACK_SEC"), diff --git a/kis_trader/engine/updown_box.py b/kis_trader/engine/updown_box.py index 5e93488..31e1724 100644 --- a/kis_trader/engine/updown_box.py +++ b/kis_trader/engine/updown_box.py @@ -447,6 +447,89 @@ def eval_box_exit_at_price( # ---------------------------------------------------------------------- # ๋ฐฑํ…Œ์ŠคํŠธ ๋Ÿฌ๋„ˆ (์‹ค๋งค์™€ ๋™์ผ ์ง„์ž…/์ฒญ์‚ฐ ๋กœ์ง ๊ณต์œ ) # ---------------------------------------------------------------------- +def run_box_backtest_rust_experimental( + candles: List[Dict[str, Any]], + cfg: Dict[str, float] +) -> Dict[str, Any]: + try: + import kis_rust_core + except ImportError: + raise RuntimeError("kis_rust_core module is not available") + + def get_float(k, default=0.0): + try: return float(cfg.get(k, default)) + except: return float(default) + + def get_int(k, default=0): + try: return int(cfg.get(k, default)) + except: return int(default) + + rust_params = kis_rust_core.BoxParams( + get_int("lookback_bars", 20), + get_float("range_max_pct", 8.0), + get_int("bb_period", 20), + get_float("bb_std", 2.0), + get_float("bb_bw_max", 12.0), + get_int("ma_period", 20), + get_float("ma_slope_tol_pct", 0.5), + get_float("stop_loss_pct", 2.5), + get_float("tp_pct", 3.0), + get_int("max_hold_bars", 64), + ) + + rust_candles = [] + # ๋ณดํ†ต ๋‹จ์ผ ์ข…๋ชฉ ํ…Œ์ŠคํŠธ + target_code = "000000" # dummy + if candles and "code" in candles[0]: + target_code = candles[0]["code"] + + for c in candles: + rc = kis_rust_core.CandleData( + c.get("candle_time", ""), + float(c.get("open", 0)), + float(c.get("high", 0)), + float(c.get("low", 0)), + float(c.get("close", 0)), + float(c.get("volume", 0)), + float(c.get("rsi", 0.0)), + ) + rust_candles.append(rc) + + trades_rs = kis_rust_core.run_box_backtest_fast(target_code, rust_candles, rust_params) + + # ๋ฐ•์Šค๊ถŒ ๊ฒฐ๊ณผ ํฌ๋งท์œผ๋กœ ๋ณ€ํ™˜ + trades = [] + total_pnl = 0.0 + wins = 0 + for t in trades_rs: + trades.append({ + "buy_time": t.buy_time, + "sell_time": t.sell_time, + "buy_price": t.buy_price, + "sell_price": t.sell_price, + "entry_time": t.buy_time, + "exit_time": t.sell_time, + "buy": t.buy_price, + "sell": t.sell_price, + "reason": t.reason, + "pnl_pct": t.pnl_pct, + "exit_reason": t.reason + }) + total_pnl += t.pnl_pct + if t.pnl_pct > 0: + wins += 1 + + n_trades = len(trades) + win_rate = (wins / n_trades * 100) if n_trades > 0 else 0.0 + return { + "trades": trades, + "n_trades": n_trades, + "pf": 0.0, + "win_rate": win_rate, + "total_pnl": total_pnl + } + + def run_backtest_box( candles: List[Dict[str, Any]], cfg: Optional[Dict[str, float]] = None, @@ -464,6 +547,10 @@ def run_backtest_box( from .scalping_engine import _intrabar_exit_prices c = cfg or get_box_cfg_from_env() + + if c.get("use_rust", 0) == 1 or c.get("use_rust") == True: + return run_box_backtest_rust_experimental(candles, c) + n = len(candles) trades: List[Dict[str, Any]] = [] if n < int(c.get("min_bars", 20)) + 2: @@ -848,6 +935,7 @@ def run_param_search_box_multi( min_trades_total: int = 3, max_combos: int = 800, rank_by: str = "alpha", + rust_session_id: Optional[str] = None, ) -> Tuple[List[Dict[str, Any]], Dict[str, Any]]: """์—ฌ๋Ÿฌ ์ข…๋ชฉ ๋ถ„๋ด‰์„ ๊ฐ™์€ ๊ธ€๋กœ๋ฒŒ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ๋ฐฑํ…Œ โ†’ ์กฐํ•ฉ๋ณ„ ํ•ฉ์‚ฐ ์„ฑ๊ณผ. @@ -887,7 +975,53 @@ def run_param_search_box_multi( per_code: Dict[str, float] = {} per_code_alpha: Dict[str, float] = {} for code, candles in candles_by_code.items(): - bt = run_backtest_box(candles, cfg) + if rust_session_id: + try: + import kis_rust_core + def get_float(k, default=0.0): + try: return float(cfg.get(k, default)) + except: return float(default) + def get_int(k, default=0): + try: return int(cfg.get(k, default)) + except: return int(default) + + bp = kis_rust_core.BoxParams( + get_int("time_start_hm", 900), + get_int("time_end_hm", 1520), + get_float("near_low_pct", 0.02), + get_float("range_max_pct", 0.08), + get_float("bb_bw_max", 15.0), + get_float("ma_slope_tol_pct", 0.02), + get_float("body_drop_min_pct", 0.0), + get_float("breach_buffer_pct", 0.015), + get_float("panic_from_high_pct", 0.08), + get_float("stop_loss_pct", 0.03), + get_float("tp_pct", 0.05), + get_float("shoulder_min_high_pct", 0.005), + get_float("shoulder_cut_pct", 0.003), + get_int("lookback_bars", 20), + get_int("max_hold_bars", 0), + str(cfg.get("ratchet_tiers", "")), + float(cfg.get("breakout_follow", 0.0)) > 0, + get_int("max_daily", 10), + ) + r_trades = kis_rust_core.run_engine_trial_box(rust_session_id, bp) + # _convert_rust_trades ์ฝ”๋“œ๊ฐ€ ํ•„์š”ํ•˜์ง€๋งŒ, ์šฐ์„  pnl ๋“ฑ๋งŒ ํ•„์š”ํ•˜๋ฏ€๋กœ ๋‹จ์ˆœ ๊ณ„์‚ฐ + tot_pnl_code = sum(t["pnl_pct"] for t in r_trades) + bt = { + "total_pnl": tot_pnl_code, + "buy_hold_pct": (candles[-1]["close"]/candles[0]["close"] - 1.0)*100.0 if candles else 0.0, + "n_trades": len(r_trades), + "trades": r_trades, + "alpha_pct": tot_pnl_code - ((candles[-1]["close"]/candles[0]["close"] - 1.0)*100.0 if candles else 0.0) + } + except Exception as e: + import logging + logging.getLogger("kis_trader.engine").warning(f"Rust engine failed for updown_box: {e}") + bt = run_backtest_box(candles, cfg) + else: + bt = run_backtest_box(candles, cfg) + tot_pnl += float(bt["total_pnl"]) tot_bh += float(bt.get("buy_hold_pct", 0.0)) tot_trades += int(bt["n_trades"]) diff --git a/kis_trader/engine/whipsaw_filter.py b/kis_trader/engine/whipsaw_filter.py index c9eeb8c..6dff7fd 100644 --- a/kis_trader/engine/whipsaw_filter.py +++ b/kis_trader/engine/whipsaw_filter.py @@ -404,7 +404,7 @@ def merge_whipsaw_cfg_from_params( """env ๊ธฐ๋ณธ + ๋ฐฑํ…Œ/Optuna trial params ์˜ค๋ฒ„๋ ˆ์ด. ์ฝค๋ณด ํ‚ค (์—”์ง„ยทTPE ๊ณตํ†ต): - whipsaw_enabled, whipsaw_subbar_sec, whipsaw_lookback_sec, + whipsaw_filter_enabled, whipsaw_subbar_sec, whipsaw_lookback_sec, whipsaw_dip_pct, whipsaw_recovery_tol_pct, whipsaw_min_subbars """ cfg = dict(load_whipsaw_params(strategy)) @@ -414,8 +414,8 @@ def merge_whipsaw_cfg_from_params( def _has(k: str) -> bool: return k in params and params.get(k) is not None and str(params.get(k)).strip() != "" - if _has("whipsaw_enabled"): - cfg["enabled"] = str(params.get("whipsaw_enabled")).strip().lower() in ( + if _has("whipsaw_filter_enabled"): + cfg["enabled"] = str(params.get("whipsaw_filter_enabled")).strip().lower() in ( "1", "true", "t", "y", "yes", "on", ) if _has("whipsaw_subbar_sec"): diff --git a/kis_trader/execution/order_manager.py b/kis_trader/execution/order_manager.py index 6f91528..bacd8eb 100644 --- a/kis_trader/execution/order_manager.py +++ b/kis_trader/execution/order_manager.py @@ -636,6 +636,7 @@ class OrderManager: price=req.price_ref, status="SUBMITTED", raw_json=self._sell_pending_meta(req), + target_price=req.price_ref, ) wait_sec = float(get_env_int("ORDER_FILL_WAIT_SEC", 2)) fill = self.client.get_execution_by_odno( @@ -2401,6 +2402,7 @@ class OrderManager: price=req.price_ref, status="SUBMITTED", raw_json=self._buy_pending_meta(req), + target_price=req.price_ref, ) if not inserted: # ord_no PK ์ค‘๋ณต(๋™์ผ ODNO ์žฌ์ „์†ก) โ€” ๋ธŒ๋กœ์ปค ์ฃผ๋ฌธ์€ ์ด๋ฏธ ๋‚˜๊ฐ”์„ ์ˆ˜ ์žˆ์Œ @@ -2773,6 +2775,7 @@ class OrderManager: price=req.price_ref, status="SUBMITTED", raw_json=self._sell_pending_meta(req), + target_price=req.price_ref, ) # โ”€โ”€ [5] ์ฒด๊ฒฐ ํ™•์ธ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ diff --git a/kis_trader/main.py b/kis_trader/main.py index 3eb0981..f131963 100644 --- a/kis_trader/main.py +++ b/kis_trader/main.py @@ -1172,10 +1172,10 @@ class TradingOrchestrator: lag_sec = None ts_dt = payload.get("ts") che = str(payload.get("chetime") or "").strip() - if isinstance(ts_dt, datetime.datetime) and che and len(che) == 6: + if isinstance(ts_dt, dt) and che and len(che) == 6: tk_str = ts_dt.strftime("%Y%m%d") + che try: - che_dt = datetime.datetime.strptime(tk_str, "%Y%m%d%H%M%S") + che_dt = dt.strptime(tk_str, "%Y%m%d%H%M%S") lag_sec = (ts_dt - che_dt).total_seconds() except ValueError: pass @@ -1238,14 +1238,14 @@ class TradingOrchestrator: if len(snap_time) >= 14: tk_str = snap_time[:14] try: - tk_dt = datetime.datetime.strptime(tk_str, "%Y%m%d%H%M%S") + tk_dt = dt.strptime(tk_str, "%Y%m%d%H%M%S") recv_ts_raw = snap.get("recv_ts") - if isinstance(recv_ts_raw, datetime.datetime): + if isinstance(recv_ts_raw, dt): recv_dt = recv_ts_raw elif isinstance(recv_ts_raw, float): - recv_dt = datetime.datetime.fromtimestamp(recv_ts_raw) + recv_dt = dt.fromtimestamp(recv_ts_raw) else: - recv_dt = datetime.datetime.now() + recv_dt = dt.now() lag_sec = (recv_dt - tk_dt).total_seconds() except Exception: pass diff --git a/kis_trader/strategies/breakout.py b/kis_trader/strategies/breakout.py index a17a13e..efa0e2a 100644 --- a/kis_trader/strategies/breakout.py +++ b/kis_trader/strategies/breakout.py @@ -1340,6 +1340,10 @@ def run_breakout_backtest( ๋งค์ˆ˜ ์‹ ํ˜ธ๋Š” ``check_buy_signal_breakout_live`` ๋ฅผ, ๋งค๋„๋Š” ``check_sell_signal_breakout_live`` ๋ฅผ ๊ทธ๋Œ€๋กœ ํ˜ธ์ถœ โ†’ ์‹ค๋งค๋งค ๋ฃฐ 100% ๋™๋“ฑ. """ + if params.get("use_rust", False): + from kis_trader.engine.breakout_engine import run_breakout_backtest_rust_experimental + return run_breakout_backtest_rust_experimental(codes_candles, params) + # โ”€โ”€ [์„ฑ๋Šฅ] env(โ†’DB) ๊ธฐ๋ฐ˜ ๋ฐฑํ…Œ ํ”Œ๋ž˜๊ทธ๋ฅผ ์‹œ๋ฎฌ ์‹œ์ž‘ ์ „ '1ํšŒ๋งŒ' ํ•ด์„ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ # get_latest_env() ๋Š” ์บ์‹œ๊ฐ€ ์—†์–ด ํ˜ธ์ถœ๋งˆ๋‹ค env_config+config_* ๋ฅผ DB ์กฐํšŒํ•œ๋‹ค. # ๊ณผ๊ฑฐ์—” ์Šค์บ”(์Šฌ๋กฏร—์ข…๋ชฉ)ยท๋ถ„๋ด‰๋งˆ๋‹ค use_tick_dbยทtick_fallback_ohlcยทslip ์„ env ๋กœ diff --git a/kis_trader/utils/export_ticks_parquet.py b/kis_trader/utils/export_ticks_parquet.py new file mode 100644 index 0000000..d09874b --- /dev/null +++ b/kis_trader/utils/export_ticks_parquet.py @@ -0,0 +1,89 @@ +#!/usr/bin/env python3 +""" +kis_trader/utils/export_ticks_parquet.py +DB์˜ ws_ticks ๋ฐ์ดํ„ฐ๋ฅผ Parquet ํŒŒ์ผ๋กœ ๋ณ€ํ™˜ํ•˜์—ฌ ๋””์Šคํฌ์— ์ €์žฅํ•ฉ๋‹ˆ๋‹ค. +์ฃผ๊ธฐ์ ์ธ ๋ฐฑ๊ทธ๋ผ์šด๋“œ ์ž‘์—…์ด๋‚˜ On-demand ํ˜ธ์ถœ์„ ์œ„ํ•ด ์„ค๊ณ„๋˜์—ˆ์Šต๋‹ˆ๋‹ค. +""" +import os +import argparse +import sys +sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "..", ".."))) +from datetime import datetime, timedelta +import polars as pl + +from kis_trader.utils.logger import get_logger +logger = get_logger("export_ticks_parquet") +from database import TradeDB, _DB_HOST, _DB_USER, _DB_PASS, _DB_NAME, _DB_PORT + +# ์ €์žฅ ํด๋” ๊ฒฝ๋กœ ์„ค์ • +TICKS_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..", "data", "ticks")) +os.makedirs(os.path.join(TICKS_DIR, "KR"), exist_ok=True) +os.makedirs(os.path.join(TICKS_DIR, "US"), exist_ok=True) + +# Polars ์šฉ URI ์ƒ์„ฑ (connectorx) +DB_URI = f"mysql://{_DB_USER}:{_DB_PASS}@{_DB_HOST}:{_DB_PORT}/{_DB_NAME}" + +def export_day(market: str, day: str) -> bool: + """ํŠน์ • ์ผ์ž์˜ ๋ฐ์ดํ„ฐ๋ฅผ Parquet์œผ๋กœ ๋ณ€ํ™˜ํ•ฉ๋‹ˆ๋‹ค (day: YYYYMMDD)""" + market = market.strip().upper() + table = "ws_ticks_us" if market == "US" else "ws_ticks" + + start_str = f"{day}000000" + end_str = f"{day}235959" + + # ์ฟผ๋ฆฌ ์ž‘์„ฑ (MariaDB์—์„œ ์ง์ ‘ Polars๋กœ ๋กœ๋“œ) + query = f""" + SELECT code, tick_time, price, volume, source, recv_ts, tick_time_raw + FROM {table} + WHERE market = '{market}' + AND tick_time >= '{start_str}' + AND tick_time <= '{end_str}' + """ + + out_file = os.path.join(TICKS_DIR, market, f"{day}.parquet") + + try: + logger.info(f"[{market}] {day} ํ‹ฑ ๋ฐ์ดํ„ฐ ๋กœ๋”ฉ ์ค‘... ({table})") + # polars์˜ read_database ์‚ฌ์šฉ (connectorx ๋ฐฑ์—”๋“œ ์‚ฌ์šฉ ์‹œ ๋งค์šฐ ๋น ๋ฆ„, ๊ธฐ๋ณธ adbc) + # pip install adbc-driver-mysql ๋ฅผ ๊ถŒ์žฅํ•˜์ง€๋งŒ ์ผ๋‹จ pandas ํด๋ฐฑ ํ˜น์€ pyarrow ํ™œ์šฉ + df = pl.read_database_uri(query, uri=DB_URI) + + if df.height == 0: + logger.warning(f"[{market}] {day} ๋ฐ์ดํ„ฐ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.") + return False + + logger.info(f"[{market}] {day} ๋กœ๋”ฉ ์™„๋ฃŒ ({df.height} rows). Parquet ์ €์žฅ ์‹œ์ž‘...") + df.write_parquet(out_file) + logger.info(f"[{market}] {day} Parquet ์ €์žฅ ์™„๋ฃŒ: {out_file}") + return True + except Exception as e: + logger.error(f"[{market}] {day} Parquet ์ €์žฅ ์‹คํŒจ: {e}") + return False + +def main(): + parser = argparse.ArgumentParser(description="ํ‹ฑ ๋ฐ์ดํ„ฐ Parquet ์ต์Šคํฌํ„ฐ") + parser.add_argument("--market", type=str, default="KR", help="๋งˆ์ผ“ (KR/US)") + parser.add_argument("--start", type=str, help="์‹œ์ž‘์ผ (YYYY-MM-DD)") + parser.add_argument("--end", type=str, help="์ข…๋ฃŒ์ผ (YYYY-MM-DD)") + + args = parser.parse_args() + + if not args.start or not args.end: + logger.error("start ์™€ end ์ธ์ž๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.") + return + + try: + start_dt = datetime.strptime(args.start, "%Y-%m-%d") + end_dt = datetime.strptime(args.end, "%Y-%m-%d") + except Exception as e: + logger.error(f"๋‚ ์งœ ํ˜•์‹ ์˜ค๋ฅ˜: {e}") + return + + cur_dt = start_dt + while cur_dt <= end_dt: + day_str = cur_dt.strftime("%Y%m%d") + export_day(args.market, day_str) + cur_dt += timedelta(days=1) + +if __name__ == "__main__": + main() diff --git a/kis_trader/ws/kis_ws.py b/kis_trader/ws/kis_ws.py index 3762672..76712b0 100644 --- a/kis_trader/ws/kis_ws.py +++ b/kis_trader/ws/kis_ws.py @@ -2689,6 +2689,46 @@ class KiwoomTokenManager: self._token: Optional[str] = None self._expiry: Optional[_datetime] = None self._lock = _threading.Lock() + + # ํŒŒ์ผ ์บ์‹œ ๊ฒฝ๋กœ ์„ค์ • (์‹ค๋งค๋งค ๋ด‡๊ณผ ๋ฐฑํ…Œ์ŠคํŠธ ๊ฐ„ ํ† ํฐ ๊ณต์œ ) + import os + base_dir = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) + self._cache_file = os.path.join(base_dir, f".kiwoom_token_cache_{'mock' if is_mock else 'real'}.json") + self._load_cache() + + def _load_cache(self) -> None: + import os, json + if not os.path.exists(self._cache_file): + return + try: + with open(self._cache_file, "r") as f: + data = json.load(f) + if data.get("app_key") != self._app_key[:10]: # ํ‚ค๊ฐ€ ๋‹ค๋ฅด๋ฉด ๋ฌดํšจ + return + tk = data.get("token") + exp = data.get("expiry") + if tk and exp: + self._token = tk + self._expiry = _datetime.fromisoformat(exp) + if not self._is_valid(): + self._token = None + self._expiry = None + except Exception as e: + logger.warning("ํ‚ค์›€ ํ† ํฐ ์บ์‹œ ๋กœ๋“œ ์‹คํŒจ: %s", e) + + def _save_cache(self) -> None: + import json + if not self._token or not self._expiry: + return + try: + with open(self._cache_file, "w") as f: + json.dump({ + "app_key": self._app_key[:10], + "token": self._token, + "expiry": self._expiry.isoformat() + }, f) + except Exception as e: + logger.warning("ํ‚ค์›€ ํ† ํฐ ์บ์‹œ ์ €์žฅ ์‹คํŒจ: %s", e) def _is_valid(self) -> bool: """๋งŒ๋ฃŒ 30์ดˆ ์ „๊นŒ์ง€ ์œ ํšจ (TokenManager._is_access_token_valid ์™€ ๋™์ผ)""" @@ -2726,6 +2766,7 @@ class KiwoomTokenManager: "โœ… ํ‚ค์›€ ํ† ํฐ ๋ฐœ๊ธ‰ ์™„๋ฃŒ [%s] (์•ž8์ž: %sโ€ฆ, ๋งŒ๋ฃŒ: %s)", self._mode_str, token[:8], self._expiry.strftime("%Y-%m-%d %H:%M:%S"), ) + self._save_cache() def invalidate(self, reason: str = "") -> None: """์„œ๋ฒ„๊ฐ€ ํ† ํฐ์„ ๊ฑฐ๋ถ€ํ–ˆ์„ ๋•Œ ๋กœ์ปฌ ์บ์‹œ๋ฅผ ๋น„์šด๋‹ค (๋งŒ๋ฃŒ ์ „ ์žฌ์‚ฌ์šฉ ๊ธˆ์ง€). diff --git a/kis_trader/ws/test_kiwoom_token_cache.py b/kis_trader/ws/test_kiwoom_token_cache.py new file mode 100644 index 0000000..316e869 --- /dev/null +++ b/kis_trader/ws/test_kiwoom_token_cache.py @@ -0,0 +1,3 @@ +import json +import os +print("OK") diff --git a/logs/kis_api_rejects.jsonl b/logs/kis_api_rejects.jsonl index 418aac6..dd4ea9d 100644 --- a/logs/kis_api_rejects.jsonl +++ b/logs/kis_api_rejects.jsonl @@ -5160,3 +5160,12 @@ {"ts": "2026-09-02T15:52:23+09:00", "kind": "domestic_order_reject", "strategy_id": "", "side": "SELL", "code": "388050", "msg_cd": "40580000", "msg1": "๋ชจ์˜ํˆฌ์ž ์žฅ์ข…๋ฃŒ ์ž…๋‹ˆ๋‹ค.", "rt_cd": "1", "http": 200, "path": "/uapi/domestic-stock/v1/trading/order-cash", "fingerprint": "7e7071dd88f5568f", "extra": {"mock": true}} {"ts": "2026-09-02T15:55:38+09:00", "kind": "domestic_order_reject", "strategy_id": "", "side": "SELL", "code": "361610", "msg_cd": "40580000", "msg1": "๋ชจ์˜ํˆฌ์ž ์žฅ์ข…๋ฃŒ ์ž…๋‹ˆ๋‹ค.", "rt_cd": "1", "http": 200, "path": "/uapi/domestic-stock/v1/trading/order-cash", "fingerprint": "303a593620b3bfef", "extra": {"mock": true}} {"ts": "2026-09-02T15:56:24+09:00", "kind": "domestic_order_reject", "strategy_id": "", "side": "SELL", "code": "388050", "msg_cd": "40580000", "msg1": "๋ชจ์˜ํˆฌ์ž ์žฅ์ข…๋ฃŒ ์ž…๋‹ˆ๋‹ค.", "rt_cd": "1", "http": 200, "path": "/uapi/domestic-stock/v1/trading/order-cash", "fingerprint": "7e7071dd88f5568f", "extra": {"mock": true}} +{"ts": "2026-09-03T14:32:15+09:00", "kind": "domestic_order_exception", "strategy_id": "", "side": "BUY", "code": "006360", "msg_cd": "EXC", "msg1": "int() argument must be a string, a bytes-like object or a real number, not 'NoneType'", "rt_cd": "", "http": "", "path": "/uapi/domestic-stock/v1/trading/order-cash", "fingerprint": "1bc31d7542fe3ebb", "extra": {"mock": true}} +{"ts": "2026-09-03T14:34:06+09:00", "kind": "domestic_order_exception", "strategy_id": "", "side": "BUY", "code": "013580", "msg_cd": "EXC", "msg1": "int() argument must be a string, a bytes-like object or a real number, not 'NoneType'", "rt_cd": "", "http": "", "path": "/uapi/domestic-stock/v1/trading/order-cash", "fingerprint": "6b2785439cfce5bb", "extra": {"mock": true}} +{"ts": "2026-09-03T14:37:14+09:00", "kind": "domestic_order_exception", "strategy_id": "", "side": "BUY", "code": "003010", "msg_cd": "EXC", "msg1": "int() argument must be a string, a bytes-like object or a real number, not 'NoneType'", "rt_cd": "", "http": "", "path": "/uapi/domestic-stock/v1/trading/order-cash", "fingerprint": "f8b29d01774452c5", "extra": {"mock": true}} +{"ts": "2026-09-03T14:40:57+09:00", "kind": "domestic_order_exception", "strategy_id": "", "side": "BUY", "code": "033640", "msg_cd": "EXC", "msg1": "int() argument must be a string, a bytes-like object or a real number, not 'NoneType'", "rt_cd": "", "http": "", "path": "/uapi/domestic-stock/v1/trading/order-cash", "fingerprint": "19411325e6509ae3", "extra": {"mock": true}} +{"ts": "2026-09-03T15:30:35+09:00", "kind": "domestic_order_reject", "strategy_id": "", "side": "SELL", "code": "037440", "msg_cd": "40580000", "msg1": "๋ชจ์˜ํˆฌ์ž ์žฅ์ข…๋ฃŒ ์ž…๋‹ˆ๋‹ค.", "rt_cd": "1", "http": 200, "path": "/uapi/domestic-stock/v1/trading/order-cash", "fingerprint": "753a4e6d3594d428", "extra": {"mock": true}} +{"ts": "2026-09-03T15:30:40+09:00", "kind": "domestic_order_reject", "strategy_id": "", "side": "SELL", "code": "053260", "msg_cd": "40580000", "msg1": "๋ชจ์˜ํˆฌ์ž ์žฅ์ข…๋ฃŒ ์ž…๋‹ˆ๋‹ค.", "rt_cd": "1", "http": 200, "path": "/uapi/domestic-stock/v1/trading/order-cash", "fingerprint": "eb862d482908c3dc", "extra": {"mock": true}} +{"ts": "2026-09-03T15:30:57+09:00", "kind": "domestic_order_reject", "strategy_id": "", "side": "BUY", "code": "039980", "msg_cd": "40580000", "msg1": "๋ชจ์˜ํˆฌ์ž ์žฅ์ข…๋ฃŒ ์ž…๋‹ˆ๋‹ค.", "rt_cd": "1", "http": 200, "path": "/uapi/domestic-stock/v1/trading/order-cash", "fingerprint": "6728ad34f1c44c95", "extra": {"mock": true}} +{"ts": "2026-09-03T15:30:57+09:00", "kind": "domestic_order_reject", "strategy_id": "", "side": "BUY", "code": "333430", "msg_cd": "40580000", "msg1": "๋ชจ์˜ํˆฌ์ž ์žฅ์ข…๋ฃŒ ์ž…๋‹ˆ๋‹ค.", "rt_cd": "1", "http": 200, "path": "/uapi/domestic-stock/v1/trading/order-cash", "fingerprint": "5c6b97e85ab4f50c", "extra": {"mock": true}} +{"ts": "2026-09-04T15:16:52+09:00", "kind": "domestic_order_reject", "strategy_id": "", "side": "SELL", "code": "003010", "msg_cd": "40240000", "msg1": "๋ชจ์˜ํˆฌ์ž ์ž”๊ณ ๋‚ด์—ญ์ด ์—†์Šต๋‹ˆ๋‹ค.", "rt_cd": "1", "http": 200, "path": "/uapi/domestic-stock/v1/trading/order-cash", "fingerprint": "df5453aa0ad46d2a", "extra": {"mock": true}} diff --git a/logs/ls_ws_observe_20260903_083501_summary.md b/logs/ls_ws_observe_20260903_083501_summary.md new file mode 100644 index 0000000..6539ee7 --- /dev/null +++ b/logs/ls_ws_observe_20260903_083501_summary.md @@ -0,0 +1,54 @@ +- since: `2026-09-03 07:00:00` +- until: `now` +- journal ์ด ์ค„: 437 + +# LS WS ์ €๋„ ๊ด€์ธก ์š”์•ฝ + +- ์ƒ์„ฑ: `2026-09-03 08:35:01` +- ์œ ๋‹›: `kis_trader_main.service` +- ๋งค์นญ ์ค„ ์ˆ˜: **75** + +## ์นด์šดํŠธ + +| ํ•ญ๋ชฉ | ๊ฑด์ˆ˜ | +|---|---:| +| LS WS OPEN | 4 | +| LS WS CLOSE | 1 | +| Bye / opcode=8 | 6 | +| LS WS RSP | 59 | +| LS WS ERROR | 0 | +| hold ๊ด€๋ จ | 1 | + +## OPEN `sendsโ‰ˆN` ๋ถ„ํฌ + +| ๊ฐ’ | ๊ฑด์ˆ˜ | +|---|---:| +| `15` | 2 | + +## OPEN `abort_why` + +| ๊ฐ’ | ๊ฑด์ˆ˜ | +|---|---:| +| `-` | 2 | + +## CLOSE/ERROR `ws_same` + +| ๊ฐ’ | ๊ฑด์ˆ˜ | +|---|---:| +| `True` | 1 | + +## RSP `rsp_cd` + +| ๊ฐ’ | ๊ฑด์ˆ˜ | +|---|---:| +| `00000` | 59 | + +## ํžŒํŠธ (๊ฐ€์„ค, ๋‹จ์ • ์•„๋‹˜) + +- Bye/opcode8 โ‰ˆ6, OPENโ‰ˆ4 โ†’ ์—ฐ๊ฒฐ ๋ฐ˜๋ณต ๋Š๊น€. + +## ๋‹ค์Œ ์•ก์…˜ + +- `sendsโ‰ˆ1` ๋‹ค์ˆ˜ + Bye โ†’ REG ์ค‘๋‹จ ์›์ธ (`abort_why`, `ws_same`) ๋Œ€์กฐ +- RSP non-00000 โ†’ ์„œ๋ฒ„ ๊ฑฐ์ ˆ ๋ฉ”์‹œ์ง€ ํ™•์ธ +- hold ์™ธ๋งŒ ๋ณด์ด๋ฉด **07:00 ์ดํ›„** ์žฌ์‹คํ–‰ diff --git a/logs/ls_ws_observe_20260903_201221_summary.md b/logs/ls_ws_observe_20260903_201221_summary.md new file mode 100644 index 0000000..ef8d07c --- /dev/null +++ b/logs/ls_ws_observe_20260903_201221_summary.md @@ -0,0 +1,69 @@ +- since: `2026-09-03 07:00:00` +- until: `now` +- journal ์ด ์ค„: 2926891 + +# LS WS ์ €๋„ ๊ด€์ธก ์š”์•ฝ + +- ์ƒ์„ฑ: `2026-09-03 20:12:21` +- ์œ ๋‹›: `kis_trader_main.service` +- ๋งค์นญ ์ค„ ์ˆ˜: **61641** + +## ์นด์šดํŠธ + +| ํ•ญ๋ชฉ | ๊ฑด์ˆ˜ | +|---|---:| +| LS WS OPEN | 90 | +| LS WS CLOSE | 46 | +| Bye / opcode=8 | 132 | +| LS WS RSP | 27831 | +| LS WS ERROR | 41 | +| hold ๊ด€๋ จ | 5 | + +## OPEN `sendsโ‰ˆN` ๋ถ„ํฌ + +| ๊ฐ’ | ๊ฑด์ˆ˜ | +|---|---:| +| `707` | 7 | +| `551` | 5 | +| `641` | 4 | +| `611` | 2 | +| `613` | 2 | +| `629` | 2 | +| `651` | 2 | +| `657` | 2 | +| `705` | 2 | +| `15` | 1 | +| `537` | 1 | +| `539` | 1 | +| `543` | 1 | +| `549` | 1 | +| `555` | 1 | + +## OPEN `abort_why` + +| ๊ฐ’ | ๊ฑด์ˆ˜ | +|---|---:| +| `-` | 45 | + +## CLOSE/ERROR `ws_same` + +| ๊ฐ’ | ๊ฑด์ˆ˜ | +|---|---:| +| `True` | 46 | +| `err:True` | 41 | + +## RSP `rsp_cd` + +| ๊ฐ’ | ๊ฑด์ˆ˜ | +|---|---:| +| `00000` | 27831 | + +## ํžŒํŠธ (๊ฐ€์„ค, ๋‹จ์ • ์•„๋‹˜) + +- Bye/opcode8 โ‰ˆ132, OPENโ‰ˆ90 โ†’ ์—ฐ๊ฒฐ ๋ฐ˜๋ณต ๋Š๊น€. + +## ๋‹ค์Œ ์•ก์…˜ + +- `sendsโ‰ˆ1` ๋‹ค์ˆ˜ + Bye โ†’ REG ์ค‘๋‹จ ์›์ธ (`abort_why`, `ws_same`) ๋Œ€์กฐ +- RSP non-00000 โ†’ ์„œ๋ฒ„ ๊ฑฐ์ ˆ ๋ฉ”์‹œ์ง€ ํ™•์ธ +- hold ์™ธ๋งŒ ๋ณด์ด๋ฉด **07:00 ์ดํ›„** ์žฌ์‹คํ–‰ diff --git a/logs/ls_ws_observe_20260904_083501_summary.md b/logs/ls_ws_observe_20260904_083501_summary.md new file mode 100644 index 0000000..573a195 --- /dev/null +++ b/logs/ls_ws_observe_20260904_083501_summary.md @@ -0,0 +1,52 @@ +- since: `2026-09-04 07:00:00` +- until: `now` +- journal ์ด ์ค„: 224 + +# LS WS ์ €๋„ ๊ด€์ธก ์š”์•ฝ + +- ์ƒ์„ฑ: `2026-09-04 08:35:01` +- ์œ ๋‹›: `kis_trader_main.service` +- ๋งค์นญ ์ค„ ์ˆ˜: **31** + +## ์นด์šดํŠธ + +| ํ•ญ๋ชฉ | ๊ฑด์ˆ˜ | +|---|---:| +| LS WS OPEN | 2 | +| LS WS CLOSE | 0 | +| Bye / opcode=8 | 4 | +| LS WS RSP | 23 | +| LS WS ERROR | 0 | +| hold ๊ด€๋ จ | 0 | + +## OPEN `sendsโ‰ˆN` ๋ถ„ํฌ + +| ๊ฐ’ | ๊ฑด์ˆ˜ | +|---|---:| +| `15` | 1 | + +## OPEN `abort_why` + +| ๊ฐ’ | ๊ฑด์ˆ˜ | +|---|---:| +| `-` | 1 | + +## CLOSE/ERROR `ws_same` + +_์—†์Œ_ + +## RSP `rsp_cd` + +| ๊ฐ’ | ๊ฑด์ˆ˜ | +|---|---:| +| `00000` | 23 | + +## ํžŒํŠธ (๊ฐ€์„ค, ๋‹จ์ • ์•„๋‹˜) + +- ํŠน์ด ์‹œ๊ทธ๋‹ˆ์ฒ˜ ๋ถ€์กฑ โ€” ์ƒ˜ํ”Œยท์‹œ๊ฐ„๋Œ€ ํ™•์ธ. + +## ๋‹ค์Œ ์•ก์…˜ + +- `sendsโ‰ˆ1` ๋‹ค์ˆ˜ + Bye โ†’ REG ์ค‘๋‹จ ์›์ธ (`abort_why`, `ws_same`) ๋Œ€์กฐ +- RSP non-00000 โ†’ ์„œ๋ฒ„ ๊ฑฐ์ ˆ ๋ฉ”์‹œ์ง€ ํ™•์ธ +- hold ์™ธ๋งŒ ๋ณด์ด๋ฉด **07:00 ์ดํ›„** ์žฌ์‹คํ–‰ diff --git a/logs/ls_ws_observe_20260904_201212_summary.md b/logs/ls_ws_observe_20260904_201212_summary.md new file mode 100644 index 0000000..652b541 --- /dev/null +++ b/logs/ls_ws_observe_20260904_201212_summary.md @@ -0,0 +1,69 @@ +- since: `2026-09-04 07:00:00` +- until: `now` +- journal ์ด ์ค„: 2910672 + +# LS WS ์ €๋„ ๊ด€์ธก ์š”์•ฝ + +- ์ƒ์„ฑ: `2026-09-04 20:12:12` +- ์œ ๋‹›: `kis_trader_main.service` +- ๋งค์นญ ์ค„ ์ˆ˜: **60630** + +## ์นด์šดํŠธ + +| ํ•ญ๋ชฉ | ๊ฑด์ˆ˜ | +|---|---:| +| LS WS OPEN | 274 | +| LS WS CLOSE | 138 | +| Bye / opcode=8 | 409 | +| LS WS RSP | 50473 | +| LS WS ERROR | 134 | +| hold ๊ด€๋ จ | 4 | + +## OPEN `sendsโ‰ˆN` ๋ถ„ํฌ + +| ๊ฐ’ | ๊ฑด์ˆ˜ | +|---|---:| +| `389` | 18 | +| `373` | 12 | +| `383` | 11 | +| `409` | 8 | +| `375` | 7 | +| `381` | 6 | +| `407` | 6 | +| `423` | 5 | +| `369` | 4 | +| `421` | 4 | +| `351` | 3 | +| `379` | 3 | +| `391` | 3 | +| `219` | 2 | +| `251` | 2 | + +## OPEN `abort_why` + +| ๊ฐ’ | ๊ฑด์ˆ˜ | +|---|---:| +| `-` | 137 | + +## CLOSE/ERROR `ws_same` + +| ๊ฐ’ | ๊ฑด์ˆ˜ | +|---|---:| +| `True` | 138 | +| `err:True` | 134 | + +## RSP `rsp_cd` + +| ๊ฐ’ | ๊ฑด์ˆ˜ | +|---|---:| +| `00000` | 50473 | + +## ํžŒํŠธ (๊ฐ€์„ค, ๋‹จ์ • ์•„๋‹˜) + +- Bye/opcode8 โ‰ˆ409, OPENโ‰ˆ274 โ†’ ์—ฐ๊ฒฐ ๋ฐ˜๋ณต ๋Š๊น€. + +## ๋‹ค์Œ ์•ก์…˜ + +- `sendsโ‰ˆ1` ๋‹ค์ˆ˜ + Bye โ†’ REG ์ค‘๋‹จ ์›์ธ (`abort_why`, `ws_same`) ๋Œ€์กฐ +- RSP non-00000 โ†’ ์„œ๋ฒ„ ๊ฑฐ์ ˆ ๋ฉ”์‹œ์ง€ ํ™•์ธ +- hold ์™ธ๋งŒ ๋ณด์ด๋ฉด **07:00 ์ดํ›„** ์žฌ์‹คํ–‰ diff --git a/logs/opt_20260904_132047_seq_seq_active.txt b/logs/opt_20260904_132047_seq_seq_active.txt new file mode 100644 index 0000000..6ad6c41 --- /dev/null +++ b/logs/opt_20260904_132047_seq_seq_active.txt @@ -0,0 +1,6 @@ +strategy=breakout +entry_mode= +sl_mode=atr +ob_mode=on +extra=atr_ob_on +refine_state_path=logs/opt_20260904_132047_seq_breakout_atr_ob_on_20260904_140407_refine_state.json diff --git a/logs/opt_20260904_151322_seq_seq_active.txt b/logs/opt_20260904_151322_seq_seq_active.txt new file mode 100644 index 0000000..a7a7626 --- /dev/null +++ b/logs/opt_20260904_151322_seq_seq_active.txt @@ -0,0 +1,6 @@ +strategy=breakout +entry_mode= +sl_mode=atr +ob_mode=on +extra=atr_ob_on +refine_state_path=logs/opt_20260904_151322_seq_breakout_atr_ob_on_20260904_160139_refine_state.json diff --git a/logs/opt_20260904_203051_seq_seq_active.txt b/logs/opt_20260904_203051_seq_seq_active.txt new file mode 100644 index 0000000..cf2cec4 --- /dev/null +++ b/logs/opt_20260904_203051_seq_seq_active.txt @@ -0,0 +1,6 @@ +strategy=tail +entry_mode=limit_atr +sl_mode= +ob_mode=off +extra=limit_atr +refine_state_path=logs/opt_20260904_203051_seq_tail_limit_atr_20260904_204023_refine_state.json diff --git a/logs/opt_20260905_010940_seq_seq_active.txt b/logs/opt_20260905_010940_seq_seq_active.txt new file mode 100644 index 0000000..437ce02 --- /dev/null +++ b/logs/opt_20260905_010940_seq_seq_active.txt @@ -0,0 +1,6 @@ +strategy=breakout +entry_mode= +sl_mode=fixed +ob_mode=on +extra=fixed_ob_on +refine_state_path=logs/opt_20260905_010940_seq_breakout_fixed_ob_on_20260905_011201_refine_state.json diff --git a/logs/opt_20260905_012016_seq_seq_active.txt b/logs/opt_20260905_012016_seq_seq_active.txt new file mode 100644 index 0000000..2c6d7f3 --- /dev/null +++ b/logs/opt_20260905_012016_seq_seq_active.txt @@ -0,0 +1,6 @@ +strategy=breakout +entry_mode= +sl_mode=atr +ob_mode=on +extra=atr_ob_on +refine_state_path=logs/opt_20260905_012016_seq_breakout_atr_ob_on_20260905_012824_refine_state.json diff --git a/logs/optuna_4strat_tpe_latest_master.logpath b/logs/optuna_4strat_tpe_latest_master.logpath index 9892f4f..8de90d7 100644 --- a/logs/optuna_4strat_tpe_latest_master.logpath +++ b/logs/optuna_4strat_tpe_latest_master.logpath @@ -1 +1 @@ -logs/optuna_4strat_tpe_2026-08-24_2026-08-28_20260903_022819_master.log +logs/optuna_4strat_tpe_2026-09-04_2026-09-04_20260905_012016_master.log diff --git a/logs/optuna_apply_audit.jsonl b/logs/optuna_apply_audit.jsonl index bc0f90c..5c28367 100644 --- a/logs/optuna_apply_audit.jsonl +++ b/logs/optuna_apply_audit.jsonl @@ -3,3 +3,4 @@ {"ts": "2026-08-28T01:04:00", "ok": true, "strategy": "momentum", "source": "mode", "rank": 1, "upto": "full", "trial": null, "job_id": "import_optuna_momentum_tpe_20260828_004239", "study_name": "momentum_tpe_20260818_20260828_20260828_000746", "result_json": "/home/hoon/kis_bot/kis_trader/backtest/results/optuna_momentum_tpe_20260828_004239.json", "params": {"tp_pct": 1.5, "sl_pct": 2.0, "tp_max_pct": 18.0, "trail_pct": 0.5, "trail_arm_pct": 2.8000000000000003, "shoulder_min_high": 3.8, "shoulder_cut_pct": 0.15000000000000002}, "metrics": {"total_pnl": 52576.0, "total_trades": 22, "win_rate": 72.73, "pf": 2.21, "optuna_trial_number": null}, "error": null, "note": "TIME_* ๋Š” session_env_patch ๊ธฐ๋ณธ OFF โ€” ์šด์˜ ์‹œ๊ฐ„์ฐฝ ์œ ์ง€ ยท ์ค„์ „์ฒด ์ ์šฉ(ํƒ€์ ยท์ต์ ˆยท์†์ ˆยทํ˜ธ๊ฐ€ยทํœฉ์˜) ยท upto=full ยท ๋ณธ trial ํ˜ธ๊ฐ€/ํœฉ์˜ ONยทOFFยท์ˆ˜์น˜ ์œ ์ง€(์‚ฌํ›„8๋ฐฉ ๋ฏธ์ ์šฉ) ยท ์›น ํผ์€ DB๋กœ ๋‹ค์‹œ ์ฑ„์›€(์ƒˆ๋กœ๊ณ ์นจ ๋ถˆํ•„์š”)"} {"ts": "2026-08-28T03:59:33", "ok": true, "strategy": "momentum", "source": "mode", "rank": 1, "upto": "full", "trial": null, "job_id": "import_optuna_momentum_tpe_20260828_033914", "study_name": "momentum_tpe_20260818_20260828_20260828_031938", "result_json": "/home/hoon/kis_bot/kis_trader/backtest/results/optuna_momentum_tpe_20260828_033914.json", "params": {"tp_pct": 1.5, "sl_pct": 6.5, "tp_max_pct": 14.0, "trail_pct": 2.4000000000000004, "trail_arm_pct": 1.4000000000000001, "shoulder_min_high": 0.9000000000000001, "shoulder_cut_pct": 0.05}, "metrics": {"total_pnl": 45002.0, "total_trades": 52, "win_rate": 69.23, "pf": 1.58, "optuna_trial_number": null}, "error": null, "note": "TIME_* ๋Š” session_env_patch ๊ธฐ๋ณธ OFF โ€” ์šด์˜ ์‹œ๊ฐ„์ฐฝ ์œ ์ง€ ยท ์ค„์ „์ฒด ์ ์šฉ(ํƒ€์ ยท์ต์ ˆยท์†์ ˆยทํ˜ธ๊ฐ€ยทํœฉ์˜) ยท upto=full ยท ๋ณธ trial ํ˜ธ๊ฐ€/ํœฉ์˜ ONยทOFFยท์ˆ˜์น˜ ์œ ์ง€(์‚ฌํ›„8๋ฐฉ ๋ฏธ์ ์šฉ) ยท ์›น ํผ์€ DB๋กœ ๋‹ค์‹œ ์ฑ„์›€(์ƒˆ๋กœ๊ณ ์นจ ๋ถˆํ•„์š”)"} {"ts": "2026-09-01T08:25:45", "ok": true, "strategy": "tail", "source": "gated", "rank": 3, "upto": "full", "trial": 92, "job_id": "import_optuna_tail_tpe_20260830_115645", "study_name": "tail_tpe_refine2_20260824_20260828_20260830_110916", "result_json": "/home/hoon/kis_bot/kis_trader/backtest/results/optuna_tail_tpe_20260830_115645.json", "params": {"tp_pct": 0.05, "sl_pct": 0.03, "trail_pct": 0.0, "trail_arm_pct": 0.0, "shoulder_min_high": 0.006, "shoulder_cut_pct": 0.001}, "metrics": {"total_pnl": 42507.0, "total_trades": 24, "win_rate": 87.5, "pf": 4.4, "optuna_trial_number": 92}, "error": null, "note": "TIME_* ๋Š” session_env_patch ๊ธฐ๋ณธ OFF โ€” ์šด์˜ ์‹œ๊ฐ„์ฐฝ ์œ ์ง€ ยท ์ค„์ „์ฒด ์ ์šฉ(ํƒ€์ ยท์ต์ ˆยท์†์ ˆยทํ˜ธ๊ฐ€ยทํœฉ์˜) ยท upto=full ยท ๋ณธ trial ํ˜ธ๊ฐ€/ํœฉ์˜ ONยทOFFยท์ˆ˜์น˜ ์œ ์ง€(์‚ฌํ›„8๋ฐฉ ๋ฏธ์ ์šฉ) ยท ์›น ํผ์€ DB๋กœ ๋‹ค์‹œ ์ฑ„์›€(์ƒˆ๋กœ๊ณ ์นจ ๋ถˆํ•„์š”)"} +{"ts": "2026-09-06T16:10:14", "ok": true, "strategy": "scalp", "source": "gated", "rank": 1, "upto": "base", "trial": 198, "job_id": "import_optuna_scalp_tpe_20260905_015030", "study_name": "scalp_tpe_refine2_20260904_20260904_20260905_014427", "result_json": "/home/hoon/kis_bot/kis_trader/backtest/results/optuna_scalp_tpe_20260905_015030.json", "params": {"tp_pct": 1.3, "sl_pct": 5.4, "tp_max_pct": 6.5, "drop_rate": 0.8, "trail_trigger": 0.7000000000000001, "trail_stop": 0.4, "shoulder_min_high": 0.8, "shoulder_cut_pct": 0.5}, "metrics": {"total_pnl": 47190.0, "total_trades": 361, "win_rate": 63.16, "pf": 2.75, "optuna_trial_number": 198}, "error": null, "note": "TIME_* ๋Š” session_env_patch ๊ธฐ๋ณธ OFF โ€” ์šด์˜ ์‹œ๊ฐ„์ฐฝ ์œ ์ง€ ยท ํƒ€์ /ํ›„์ฒ˜๋ฆฌ ์ ์šฉ(upto=base) ยท ํ›„์ฒ˜๋ฆฌํ‚ค SCALP_ORDERBOOK_FILTER_ENABLED,SCALP_WHIPSAW_DIP_PCT,SCALP_WHIPSAW_FILTER_ENABLED,SCALP_WHIPSAW_LOOKBACK_SEC,SCALP_WHIPSAW_MODE,SCALP_WHIPSAW_RECOVERY_TOL_PCT,SCALP_WHIPSAW_SUBBAR_SEC ยท ์›น ํผ์€ DB๋กœ ๋‹ค์‹œ ์ฑ„์›€(์ƒˆ๋กœ๊ณ ์นจ ๋ถˆํ•„์š”)"} diff --git a/logs/optuna_breakout_latest.jsonpath b/logs/optuna_breakout_latest.jsonpath index bf979e8..1e38d7d 100644 --- a/logs/optuna_breakout_latest.jsonpath +++ b/logs/optuna_breakout_latest.jsonpath @@ -1 +1 @@ -/home/hoon/kis_bot/kis_trader/backtest/results/optuna_breakout_tpe_20260830_152138.json +/home/hoon/kis_bot/kis_trader/backtest/results/optuna_breakout_tpe_20260905_013127.json diff --git a/logs/optuna_breakout_tpe_latest.jsonpath b/logs/optuna_breakout_tpe_latest.jsonpath index bf979e8..1e38d7d 100644 --- a/logs/optuna_breakout_tpe_latest.jsonpath +++ b/logs/optuna_breakout_tpe_latest.jsonpath @@ -1 +1 @@ -/home/hoon/kis_bot/kis_trader/backtest/results/optuna_breakout_tpe_20260830_152138.json +/home/hoon/kis_bot/kis_trader/backtest/results/optuna_breakout_tpe_20260905_013127.json diff --git a/logs/optuna_latest.jsonpath b/logs/optuna_latest.jsonpath index c489bc9..745059a 100644 --- a/logs/optuna_latest.jsonpath +++ b/logs/optuna_latest.jsonpath @@ -1 +1 @@ -/home/hoon/kis_bot/kis_trader/backtest/results/optuna_tail_tpe_20260903_024358.json +/home/hoon/kis_bot/kis_trader/backtest/results/optuna_scalp_tpe_20260906_131534.json diff --git a/logs/optuna_momentum_fast_latest.jsonpath b/logs/optuna_momentum_fast_latest.jsonpath index 5a2342b..246ad72 100644 --- a/logs/optuna_momentum_fast_latest.jsonpath +++ b/logs/optuna_momentum_fast_latest.jsonpath @@ -1 +1 @@ -/home/hoon/kis_bot/kis_trader/backtest/results/optuna_momentum_fast_20260826_030721.json +/home/hoon/kis_bot/kis_trader/backtest/results/optuna_momentum_fast_20260903_080828.json diff --git a/logs/optuna_momentum_latest.jsonpath b/logs/optuna_momentum_latest.jsonpath index 57b0562..c5abec0 100644 --- a/logs/optuna_momentum_latest.jsonpath +++ b/logs/optuna_momentum_latest.jsonpath @@ -1 +1 @@ -/home/hoon/kis_bot/kis_trader/backtest/results/optuna_momentum_tpe_20260830_110838.json +/home/hoon/kis_bot/kis_trader/backtest/results/optuna_momentum_tpe_20260903_200417.json diff --git a/logs/optuna_momentum_tpe_latest.jsonpath b/logs/optuna_momentum_tpe_latest.jsonpath index 57b0562..c5abec0 100644 --- a/logs/optuna_momentum_tpe_latest.jsonpath +++ b/logs/optuna_momentum_tpe_latest.jsonpath @@ -1 +1 @@ -/home/hoon/kis_bot/kis_trader/backtest/results/optuna_momentum_tpe_20260830_110838.json +/home/hoon/kis_bot/kis_trader/backtest/results/optuna_momentum_tpe_20260903_200417.json diff --git a/logs/optuna_scalp_latest.jsonpath b/logs/optuna_scalp_latest.jsonpath index 877eb50..745059a 100644 --- a/logs/optuna_scalp_latest.jsonpath +++ b/logs/optuna_scalp_latest.jsonpath @@ -1 +1 @@ -/home/hoon/kis_bot/kis_trader/backtest/results/optuna_scalp_tpe_20260830_161031.json +/home/hoon/kis_bot/kis_trader/backtest/results/optuna_scalp_tpe_20260906_131534.json diff --git a/logs/optuna_scalp_tpe_latest.jsonpath b/logs/optuna_scalp_tpe_latest.jsonpath index 877eb50..745059a 100644 --- a/logs/optuna_scalp_tpe_latest.jsonpath +++ b/logs/optuna_scalp_tpe_latest.jsonpath @@ -1 +1 @@ -/home/hoon/kis_bot/kis_trader/backtest/results/optuna_scalp_tpe_20260830_161031.json +/home/hoon/kis_bot/kis_trader/backtest/results/optuna_scalp_tpe_20260906_131534.json diff --git a/logs/optuna_tail_fast_latest.jsonpath b/logs/optuna_tail_fast_latest.jsonpath index bde3f0c..9f62531 100644 --- a/logs/optuna_tail_fast_latest.jsonpath +++ b/logs/optuna_tail_fast_latest.jsonpath @@ -1 +1 @@ -/home/hoon/kis_bot/kis_trader/backtest/results/optuna_tail_fast_20260826_030604.json +/home/hoon/kis_bot/kis_trader/backtest/results/optuna_tail_fast_20260904_232420.json diff --git a/logs/optuna_tail_latest.jsonpath b/logs/optuna_tail_latest.jsonpath index c489bc9..da56ee8 100644 --- a/logs/optuna_tail_latest.jsonpath +++ b/logs/optuna_tail_latest.jsonpath @@ -1 +1 @@ -/home/hoon/kis_bot/kis_trader/backtest/results/optuna_tail_tpe_20260903_024358.json +/home/hoon/kis_bot/kis_trader/backtest/results/optuna_tail_tpe_20260905_010412.json diff --git a/logs/optuna_tail_tpe_latest.jsonpath b/logs/optuna_tail_tpe_latest.jsonpath index c489bc9..da56ee8 100644 --- a/logs/optuna_tail_tpe_latest.jsonpath +++ b/logs/optuna_tail_tpe_latest.jsonpath @@ -1 +1 @@ -/home/hoon/kis_bot/kis_trader/backtest/results/optuna_tail_tpe_20260903_024358.json +/home/hoon/kis_bot/kis_trader/backtest/results/optuna_tail_tpe_20260905_010412.json diff --git a/logs/optuna_web_latest_job.txt b/logs/optuna_web_latest_job.txt index 6c1df49..68f7061 100644 --- a/logs/optuna_web_latest_job.txt +++ b/logs/optuna_web_latest_job.txt @@ -1 +1 @@ -opt_20260903_022819_seq +opt_20260906_162743_refine_scal diff --git a/remove/legacy_root/_verify_shared_e2e_breakout.py b/remove/legacy_root/_verify_shared_e2e_breakout.py index 7461ef8..bf3a3c2 100644 --- a/remove/legacy_root/_verify_shared_e2e_breakout.py +++ b/remove/legacy_root/_verify_shared_e2e_breakout.py @@ -17,7 +17,7 @@ from database import TradeDB from kis_trader.backtest import breakout_backtest_common as bbc from kis_trader.backtest.param_search_breakout import _load_candles_for_search from kis_trader.backtest.breakout_backtest_common import resolve_breakout_universe -from kis_trader.backtest.breakout_tick_loader import load_breakout_ticks_by_code +from kis_trader.backtest.breakout_tick_loader import load_common_ticks_by_code from kis_trader.backtest.shared_ticks import build_shared_ticks START = "2026-06-28" @@ -81,7 +81,7 @@ def main(): print("โณ ws_ticks ๋กœ๋“œ...") db = TradeDB() try: - ticks_dict, tick_rows = load_breakout_ticks_by_code( + ticks_dict, tick_rows = load_common_ticks_by_code( db, start_key, end_key, set(codes_candles.keys()), ) finally: diff --git a/scratch/add_columns.py b/scratch/add_columns.py new file mode 100644 index 0000000..6bce0e9 --- /dev/null +++ b/scratch/add_columns.py @@ -0,0 +1,33 @@ +import re + +with open('templates/backtest.html', 'r', encoding='utf-8') as f: + content = f.read() + +# "๋งค์ˆ˜๊ฐ€๋งค๋„๊ฐ€์ˆ˜๋Ÿ‰" ๊ฐ€ ์žˆ๋Š” ์ค„ ๋์— "๋ชฉํ‘œ๊ฐ€์Šฌ๋ฆฌํ”ผ์ง€%" ์ถ”๊ฐ€ +content = content.replace( + "๋งค์ˆ˜๊ฐ€๋งค๋„๊ฐ€์ˆ˜๋Ÿ‰\n", + "๋งค์ˆ˜๊ฐ€๋งค๋„๊ฐ€์ˆ˜๋Ÿ‰\n ๋ชฉํ‘œ๊ฐ€์Šฌ๋ฆฌํ”ผ์ง€%\n" +) +# ํ˜น์‹œ ๊ฐ™์€ ์ค„์— ์†์ต... ์ด ์ด์–ด์ ธ์žˆ์„ ์ˆ˜๋„ ์žˆ์œผ๋‹ˆ ํ™•์ธ +content = re.sub( + r'(๋งค์ˆ˜๊ฐ€๋งค๋„๊ฐ€์ˆ˜๋Ÿ‰)', + r'\1๋ชฉํ‘œ๊ฐ€์Šฌ๋ฆฌํ”ผ์ง€%', + content +) + +# ์ค‘๋ณต ๊ต์ฒด(์œ„ ๋‘ ๋ฒˆ ์ ์šฉ) ์‹œ ๋ฐฉ์ง€ ์œ„ํ•ด ์›๋ž˜๋Œ€๋กœ ๋ณต๊ตฌ ํ›„ ์ •๊ทœ์‹๋งŒ ์“ฐ๊ธฐ +with open('templates/backtest.html', 'r', encoding='utf-8') as f: + original = f.read() + +new_content = re.sub( + r'(๋งค์ˆ˜๊ฐ€๋งค๋„๊ฐ€์ˆ˜๋Ÿ‰)', + r'\1๋ชฉํ‘œ๊ฐ€์Šฌ๋ฆฌํ”ผ์ง€%', + original +) +# ๋งŒ์•ฝ ์ด๋ฏธ ๋“ค์–ด๊ฐ„ ๊ณณ(์‹ค๊ฑฐ๋ž˜ ํƒญ)์ด ์žˆ๋‹ค๋ฉด ์ค‘๋ณต๋  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ +new_content = new_content.replace('๋ชฉํ‘œ๊ฐ€์Šฌ๋ฆฌํ”ผ์ง€%๋ชฉํ‘œ๊ฐ€์Šฌ๋ฆฌํ”ผ์ง€%', '๋ชฉํ‘œ๊ฐ€์Šฌ๋ฆฌํ”ผ์ง€%') + +with open('templates/backtest.html', 'w', encoding='utf-8') as f: + f.write(new_content) + +print("done") diff --git a/scratch/check_cols.py b/scratch/check_cols.py new file mode 100644 index 0000000..58aa47a --- /dev/null +++ b/scratch/check_cols.py @@ -0,0 +1,7 @@ +from database import TradeDB +db = TradeDB() +try: + print("trade_history:", db.conn.get_columns("trade_history")) + print("active_trades:", db.conn.get_columns("active_trades")) +finally: + db.close() diff --git a/scratch/check_db_date.py b/scratch/check_db_date.py new file mode 100644 index 0000000..0756875 --- /dev/null +++ b/scratch/check_db_date.py @@ -0,0 +1,9 @@ +import sys +sys.path.append(".") +from database import TradeDB +db = TradeDB() +try: + res = db.conn.execute("SELECT MIN(candle_time) as min_time, MAX(candle_time) as max_time FROM ws_candles").fetchone() + print("ws_candles:", dict(res)) +finally: + db.close() diff --git a/scratch/check_db_migrate.py b/scratch/check_db_migrate.py new file mode 100644 index 0000000..445ab1e --- /dev/null +++ b/scratch/check_db_migrate.py @@ -0,0 +1,11 @@ +import logging +logging.basicConfig(level=logging.DEBUG) +from database import TradeDB +db = TradeDB() +try: + cols = [dict(r)["Field"] for r in db.conn.execute("SHOW COLUMNS FROM ls_ws_ticks").fetchall()] + print("ls_ws_ticks cols:", cols) + cols2 = [dict(r)["Field"] for r in db.conn.execute("SHOW COLUMNS FROM ls_ws_orderbook").fetchall()] + print("ls_ws_orderbook cols:", cols2) +except Exception as e: + print("Error:", e) diff --git a/scratch/check_env.py b/scratch/check_env.py index df8b1a7..9d333fc 100644 --- a/scratch/check_env.py +++ b/scratch/check_env.py @@ -1,7 +1,6 @@ from database import TradeDB +from kis_trader.utils.env import get_env_bool + db = TradeDB() -try: - cols = [dict(r) for r in db.conn.execute("SHOW COLUMNS FROM env_config").fetchall()] - print("env_config ์Šคํ‚ค๋งˆ:", cols) -finally: - db.close() +print("LS_WS_TICK_SAVE:", get_env_bool("LS_WS_TICK_SAVE", False)) +print("LS_WS_ORDERBOOK_SAVE:", get_env_bool("LS_WS_ORDERBOOK_SAVE", True)) diff --git a/scratch/check_ls_db_today.py b/scratch/check_ls_db_today.py new file mode 100644 index 0000000..5ba2b4e --- /dev/null +++ b/scratch/check_ls_db_today.py @@ -0,0 +1,20 @@ +from database import TradeDB +import datetime + +db = TradeDB() +try: + today_str = datetime.datetime.now().strftime("%Y-%m-%d") + cur = db.conn.execute("SELECT COUNT(*) AS c FROM ls_ws_ticks WHERE ts >= %s", (today_str,)) + print("ls_ws_ticks today:", dict(cur.fetchone())['c']) + + cur2 = db.conn.execute("SELECT COUNT(*) AS c FROM ls_ws_orderbook WHERE recv_ts >= %s", (today_str,)) + print("ls_ws_orderbook today:", dict(cur2.fetchone())['c']) + + cur3 = db.conn.execute("SELECT MAX(ts) AS m FROM ls_ws_ticks") + print("Max ts in ticks:", dict(cur3.fetchone())['m']) + + cur4 = db.conn.execute("SELECT MAX(recv_ts) AS m FROM ls_ws_orderbook") + print("Max recv_ts in orderbook:", dict(cur4.fetchone())['m']) + +except Exception as e: + print("Error:", e) diff --git a/scratch/check_orders_columns.py b/scratch/check_orders_columns.py new file mode 100644 index 0000000..48ef105 --- /dev/null +++ b/scratch/check_orders_columns.py @@ -0,0 +1,7 @@ +from database import TradeDB +db = TradeDB() +try: + cols = [dict(r)["Field"] for r in db.conn.execute("SHOW COLUMNS FROM orders").fetchall()] + print(f"orders cols: {cols}") +finally: + db.close() diff --git a/scratch/db_check.py b/scratch/db_check.py index 99fb597..8f97e9a 100644 --- a/scratch/db_check.py +++ b/scratch/db_check.py @@ -1,26 +1,9 @@ import sys -import os -sys.path.append('/home/hoon/kis_bot') - +sys.path.append("/home/hoon/kis_bot") from database import TradeDB -def check_db(): - db = TradeDB() - try: - # Check tables - tables = [dict(r) for r in db.conn.execute("SHOW TABLES").fetchall()] - print("Tables:", tables) - - # Let's check environment variables and settings related to slots and buying - cols_env = [dict(r)["Field"] for r in db.conn.execute("SHOW COLUMNS FROM env_settings").fetchall()] - print("env_settings cols:", cols_env) - - env_vars = db.conn.execute("SELECT * FROM env_settings").fetchall() - for env in env_vars: - print(dict(env)) - - finally: - db.close() - -if __name__ == "__main__": - check_db() +db = TradeDB() +keys = ["RSI_PERIOD", "RSI_OVERSOLD", "RSI_OVERBOUGHT", "SCALP_SL_PCT", "SCALP_TP_PCT", "SCALP_DROP_RATE", "SCALP_COOLDOWN_MIN", "SCALP_MACD_CROSS"] +for k in keys: + val = db.get_env(k) + print(f"{k}: {val}") diff --git a/scratch/find_optuna_trial.py b/scratch/find_optuna_trial.py new file mode 100644 index 0000000..88ed40b --- /dev/null +++ b/scratch/find_optuna_trial.py @@ -0,0 +1,29 @@ +import json +import glob +import sys + +files = sorted(glob.glob('/home/hoon/kis_bot/logs/optuna_web_jobs/import_optuna_scalp_*.json'), reverse=True)[:5] +files += sorted(glob.glob('/home/hoon/kis_bot/kis_trader/backtest/results/optuna_scalp_tpe_*.json'), reverse=True)[:5] + +for fpath in files: + try: + with open(fpath) as f: + data = json.load(f) + + # import ๋œ ์žก (์›น UI ์šฉ) ์ผ ๊ฒฝ์šฐ: + trials = data.get('trials', []) or data.get('optuna_trials', []) + for tr in trials: + # optuna_web_jobs/ ์— ์žˆ๋Š” json์˜ ๊ฒฝ์šฐ tr ๊ตฌ์กฐ๊ฐ€ ๋‹ค๋ฆ„. (t, p, s, attrs) + if 't' in tr: # trial number is 't' + if tr.get('t') == 198 or tr.get('attrs', {}).get('trades') == 361: + print(f"Found in {fpath}: Trial {tr.get('t')} with {tr.get('attrs', {}).get('trades')} trades") + print(json.dumps(tr.get('p', {}), indent=2, ensure_ascii=False)) + sys.exit(0) + elif 'number' in tr: + if tr.get('number') == 198 or tr.get('user_attrs', {}).get('trades') == 361: + print(f"Found in {fpath}: Trial {tr.get('number')} with {tr.get('user_attrs', {}).get('trades')} trades") + print(json.dumps(tr.get('params', {}), indent=2, ensure_ascii=False)) + sys.exit(0) + except Exception as e: + pass +print("Not found") diff --git a/scratch/fix_summaries.py b/scratch/fix_summaries.py new file mode 100644 index 0000000..e77fa50 --- /dev/null +++ b/scratch/fix_summaries.py @@ -0,0 +1,20 @@ +import sys +import glob +import json +sys.path.append("/home/hoon/kis_bot") +from kis_trader.backtest.optuna_web_jobs import load_job, save_job, _summarize_result_data, _load_out_data_for_job + +for f in glob.glob("logs/optuna_web_jobs/*.json"): + try: + with open(f) as fp: + meta = json.load(fp) + if meta.get("status") == "done": + data, path = _load_out_data_for_job(meta, meta.get("result_json")) + if data: + summ = _summarize_result_data(data, path) + if summ: + meta["result_summary"] = summ + save_job(meta) + print(f"Updated {f}") + except Exception as e: + print(f"Failed {f}: {e}") diff --git a/scratch/optuna_check.py b/scratch/optuna_check.py new file mode 100644 index 0000000..4aff924 --- /dev/null +++ b/scratch/optuna_check.py @@ -0,0 +1,18 @@ +import sys +import optuna +import json +import os + +sys.path.append("/home/hoon/kis_bot") +from kis_trader.backtest.optuna_common import resolve_optuna_storage_url + +storage = resolve_optuna_storage_url() +study_name = "scalp_tpe_refine2_20260904_20260904_20260905_014427" +try: + study = optuna.load_study(study_name=study_name, storage=storage) + trial = study.trials[160] + print(f"Trial #160 State: {trial.state}") + print(f"Trial #160 Value: {trial.value}") + print(f"Trial #160 Params: {json.dumps(trial.params, indent=2)}") +except Exception as e: + print(f"Error: {e}") diff --git a/scratch/simulate_fill.js b/scratch/simulate_fill.js new file mode 100644 index 0000000..b5386bd --- /dev/null +++ b/scratch/simulate_fill.js @@ -0,0 +1,21 @@ +const fs = require('fs'); +const glob = require('glob'); +const jobs = glob.sync('/home/hoon/kis_bot/logs/optuna_web_jobs/*.json'); +const latest = jobs.sort((a,b) => fs.statSync(b).mtime - fs.statSync(a).mtime)[0]; +console.log("Latest job:", latest); +const jobData = JSON.parse(fs.readFileSync(latest, 'utf8')); + +// Find best gated trial (usually rank 1) +const resultJsonPath = jobData.result_json || jobData.log_path.replace('.log', '.json'); +console.log("Result JSON:", resultJsonPath); +const resultData = JSON.parse(fs.readFileSync(resultJsonPath, 'utf8')); +const gated = resultData.top5_gated[0]; +console.log("Top gated params:", gated.params); + +const pTune = gated.params || {}; +const pEng = gated.params_full || {}; +const p = Object.assign({}, pEng, pTune); + +console.log("Merged sl_pct:", p.sl_pct); +console.log("Merged use_defense_filters:", p.use_defense_filters); +console.log("Merged skip_hts_scan_dupes:", p.skip_hts_scan_dupes); diff --git a/scratch/test_breakout.py b/scratch/test_breakout.py new file mode 100644 index 0000000..3f7cd10 --- /dev/null +++ b/scratch/test_breakout.py @@ -0,0 +1,14 @@ +from kis_trader.backtest.breakout_portfolio_backtest import run_breakout_backtest_web_aligned +from database import TradeDB +from kis_trader.backtest.bt_candle_source import load_backtest_candles +db = TradeDB() +try: + candles = load_backtest_candles(db, "20260904090000", "20260904153000", limit=100) + print(f"Loaded candles for {len(candles)} codes") + + # We just need to check if there are any codes + # Run a simple backtest + from kis_trader.engine.breakout_engine import BreakoutEngine + print("Test ready") +finally: + db.close() diff --git a/scratch/test_json.py b/scratch/test_json.py new file mode 100644 index 0000000..24afe1a --- /dev/null +++ b/scratch/test_json.py @@ -0,0 +1,7 @@ +import json + +with open("logs/optuna_web_jobs/opt_20260906_130912_refine_scal.json") as f: + d = json.load(f) + print("label:", repr(d.get("label"))) + print("job_id:", repr(d.get("job_id"))) + print("kind:", repr(d.get("kind"))) diff --git a/scratch/test_label.py b/scratch/test_label.py new file mode 100644 index 0000000..7d4c595 --- /dev/null +++ b/scratch/test_label.py @@ -0,0 +1,3 @@ +label = None +label = f"1ยท2์ฐจTPEยท{label}" +print(repr(label)) diff --git a/scratch/test_ls_insert.py b/scratch/test_ls_insert.py new file mode 100644 index 0000000..c79ca32 --- /dev/null +++ b/scratch/test_ls_insert.py @@ -0,0 +1,29 @@ +import logging +logging.basicConfig(level=logging.DEBUG) +from database import TradeDB +from datetime import datetime +db = TradeDB() +try: + res = db.insert_ls_ws_tick( + code="005930", + ts=datetime.now(), + price=1000, + volume=10, + tot_volume=100, + chetime="123456", + tr_cd="TEST", + tk="20260903123456", + lag_sec=1.5 + ) + print("Insert Tick Result:", res) + + res2 = db.insert_ls_ws_orderbook( + code="005930", + snap={"snap_time": "20260903123456", "best_bid": 100, "best_ask": 101}, + market="KR", + tk="20260903123456", + lag_sec=0.1 + ) + print("Insert OB Result:", res2) +except Exception as e: + print("Error:", e) diff --git a/scratch/test_merge.js b/scratch/test_merge.js new file mode 100644 index 0000000..504c1c6 --- /dev/null +++ b/scratch/test_merge.js @@ -0,0 +1,23 @@ +const fs = require('fs'); +const glob = require('glob'); +const jobs = glob.sync('/home/hoon/kis_bot/logs/optuna_web_jobs/*.json'); +const latest = jobs.sort((a,b) => fs.statSync(b).mtime - fs.statSync(a).mtime)[0]; +console.log("Latest job:", latest); +const jobData = JSON.parse(fs.readFileSync(latest, 'utf8')); + +const resultJsonPath = jobData.result_json || jobData.log_path.replace('.log', '.json'); +console.log("Result JSON:", resultJsonPath); +const resultData = JSON.parse(fs.readFileSync(resultJsonPath, 'utf8')); +const list = resultData.top5_gated || resultData.top5_as_scored || []; +if (list.length === 0) { console.log("No trials"); process.exit(1); } +const trial = list[0]; +console.log("Trial params:", trial.params); +console.log("Trial params_full:", trial.params_full); + +const pTune = trial.params || {}; +const pEng = trial.params_full || {}; +const p = Object.assign({}, pEng, pTune); + +console.log("MERGED sl_pct:", p.sl_pct); +console.log("MERGED use_defense_filters:", p.use_defense_filters); +console.log("MERGED skip_hts_scan_dupes:", p.skip_hts_scan_dupes); diff --git a/scratch/test_on_tick.py b/scratch/test_on_tick.py new file mode 100644 index 0000000..59e27a7 --- /dev/null +++ b/scratch/test_on_tick.py @@ -0,0 +1,25 @@ +from kis_trader.main import TradingOrchestrator +import datetime + +class DummyDB: + def insert_ls_ws_tick(self, **kwargs): + print("insert_ls_ws_tick", kwargs) + def insert_ls_ws_orderbook(self, **kwargs): + print("insert_ls_ws_orderbook", kwargs) + def __getattr__(self, name): + return lambda *args, **kwargs: None + +class DummyWS: + _sub_lock = type('Lock', (), {'__enter__': lambda s: None, '__exit__': lambda s, *a: None})() + _subscribed = {"005930"} + +orc = TradingOrchestrator(auto_start=False) +orc.db = DummyDB() +orc.ls_ws = DummyWS() +orc._ls_is_subscribed = lambda c: True + +def test(): + # extract _on_tick manually because it's defined inside _start_ws + # Wait, it's defined inside _start_ws, so it uses `datetime` from outer scope! + pass + diff --git a/scratch/test_row.py b/scratch/test_row.py new file mode 100644 index 0000000..207ff26 --- /dev/null +++ b/scratch/test_row.py @@ -0,0 +1,9 @@ +import sys +import json +sys.path.append("/home/hoon/kis_bot") +from kis_trader.backtest.optuna_web_jobs import job_list_row + +with open("logs/optuna_web_jobs/import_optuna_scalp_tpe_20260906_131534.json") as f: + m = json.load(f) + +print(job_list_row(m)) diff --git a/scratch/test_rust_session.py b/scratch/test_rust_session.py new file mode 100644 index 0000000..df06ec8 --- /dev/null +++ b/scratch/test_rust_session.py @@ -0,0 +1,45 @@ +import os +import sys +sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))) + +from kis_trader.engine.tail_engine import init_rust_session, clear_rust_session +import kis_rust_core + +def run_test(): + session_id = "test_session_123" + + # ๊ฐ€์ƒ์˜ ์–‘๋ด‰ ๋ฐ์ดํ„ฐ + mock_candles = { + "005930": [ + {"candle_time": "20260901093000", "open": 60000, "high": 60500, "low": 59500, "close": 59800, "rsi": 50.0}, + {"candle_time": "20260901093100", "open": 59800, "high": 61000, "low": 59000, "close": 60800, "rsi": 65.0}, + {"candle_time": "20260901093200", "open": 60800, "high": 61500, "low": 60500, "close": 61200, "rsi": 70.0}, + {"candle_time": "20260901093300", "open": 61200, "high": 62000, "low": 61000, "close": 61500, "rsi": 75.0}, + ] + } + + print("1. init_rust_session ํ˜ธ์ถœ") + init_rust_session(session_id, mock_candles, None) + + print("2. ํŒŒ๋ผ๋ฏธํ„ฐ ์ƒ์„ฑ") + tp = kis_rust_core.TailParams( + 930, 1500, 15.0, 3, 1000.0, + 78.0, 0.01, 0.5, 0.003, True, + 0.03, 0.05, 0.0, 0.0, 0.0, 0.0, + 0, 200000.0, 0.015 + ) + + print("3. run_engine_trial_tail ํ˜ธ์ถœ") + try: + trades = kis_rust_core.run_engine_trial_tail(session_id, tp) + print(f"๋ฐ˜ํ™˜๋œ trades ์ˆ˜: {len(trades)}") + for t in trades: + print(f" - [{t.code}] {t.buy_time} ~ {t.sell_time} | pnl: {t.pnl_pct:.2f}% | reason: {t.reason}") + except Exception as e: + print(f"์—๋Ÿฌ ๋ฐœ์ƒ: {e}") + + print("4. clear_rust_session ํ˜ธ์ถœ") + clear_rust_session(session_id) + +if __name__ == "__main__": + run_test() diff --git a/scratch/test_speed.py b/scratch/test_speed.py new file mode 100644 index 0000000..d61f4e7 --- /dev/null +++ b/scratch/test_speed.py @@ -0,0 +1,35 @@ +import time +import os +import sys + +sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))) +from kis_trader.engine.tail_engine import run_tail_backtest_rust_experimental +import kis_rust_core + +def test_speed(): + # ๋”๋ฏธ ๋ฐ์ดํ„ฐ ์ƒ์„ฑ + codes_candles = {} + for i in range(100): + code = f"KR{i:04d}" + codes_candles[code] = [] + for j in range(2000): # ์ข…๋ชฉ๋‹น 2000๊ฐœ ๋ด‰ (๋Œ€๋žต 2์ฃผ์น˜ 3๋ถ„๋ด‰) + codes_candles[code].append({ + "candle_time": "20260902120000", + "open": 1000, + "high": 1050, + "low": 950, + "close": 1020, + "volume": 10000, + "rsi": 50.0 + }) + + params = {} + + t0 = time.time() + run_tail_backtest_rust_experimental(codes_candles, params) + t1 = time.time() + + print(f"Time taken: {t1 - t0:.4f}s") + +if __name__ == "__main__": + test_speed() diff --git a/scratch/test_start.py b/scratch/test_start.py new file mode 100644 index 0000000..51991d2 --- /dev/null +++ b/scratch/test_start.py @@ -0,0 +1,18 @@ +import sys +from datetime import datetime +from unittest.mock import patch +sys.path.append("/home/hoon/kis_bot") +from kis_trader.backtest.optuna_web_jobs import start_optuna_job + +with patch('subprocess.Popen') as mock_popen: + mock_popen.return_value.pid = 9999 + meta = start_optuna_job( + strategy="scalp", + start="2026-09-04", + end="2026-09-04", + trials=200, + mode="tpe", + ) + print("MOCKED JOB RESULT:") + print("job_id:", meta.get("job_id")) + print("label:", meta.get("label")) diff --git a/scratch/test_tail_rust.py b/scratch/test_tail_rust.py index 809b5a4..6fa4365 100644 --- a/scratch/test_tail_rust.py +++ b/scratch/test_tail_rust.py @@ -1,48 +1,81 @@ -import time -import kis_rust_core +import os +import sys + +# Ensure kis_bot root is in path +sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))) + +from database import TradeDB +from kis_trader.backtest.tail_backtest_common import load_tail_candles_by_code +from kis_trader.engine.tail_engine import run_tail_backtest, run_tail_backtest_rust_experimental, get_tail_defaults_from_db def test_rust_tail(): - print(f"Loaded Rust Module: {kis_rust_core}") - - # 1. ํŒŒ๋ผ๋ฏธํ„ฐ ์…‹์—… - params = kis_rust_core.TailParams( - rsi_limit=45.0, - drop_pct_min=3.0, - tail_recovery_min=1.5, - target_pct=2.0, - stop_loss_pct=3.0 - ) - print(f"TailParams initialized: {params.rsi_limit}, {params.target_pct}% target") + db = TradeDB() + try: + # Load recent env params + engine_params = get_tail_defaults_from_db(db) + print(f"Engine params: {engine_params}") + + # Load candles + start_date = "2026-08-07" + end_date = "2026-08-07" + print(f"Loading candles from {start_date} to {end_date}...") + candles_by_code, _, _ = load_tail_candles_by_code(db, start_date, end_date, 3) + print(f"Loaded {len(candles_by_code)} symbols.") + + # Create Python engine + py_trades = run_tail_backtest( + candles_by_code=candles_by_code, + params=engine_params, + ) + print(f"[Python] Found {len(py_trades)} trades.") + + # Create Rust engine + rs_trades = run_tail_backtest_rust_experimental( + codes_candles=candles_by_code, + params=engine_params, + ) + print(f"[Rust] Found {len(rs_trades)} trades.") + + # Sort both + rs_trades.sort(key=lambda x: (x["code"], x["entry_time"])) + py_trades.sort(key=lambda x: (x["code"], x["entry_time"])) + + if len(rs_trades) != len(py_trades): + print(f"!!! COUNT MISMATCH !!! Rust: {len(rs_trades)}, Python: {len(py_trades)}") + + # Compare first 5 + print("\n--- Python Trades ---") + for i, t in enumerate(py_trades[:5]): + print(f"{i}: {t}") + + print("\n--- Rust Trades ---") + for i, t in enumerate(rs_trades[:5]): + print(f"{i}: {t}") + + # Check diff + print("\n--- Differences ---") + py_simple = [{"code": t["code"], "entry_time": t["entry_time"], "entry": t["entry"], "exit": t["exit"]} for t in py_trades] + rs_simple = [{"code": t["code"], "entry_time": t["entry_time"], "entry": t["entry"], "exit": t["exit"]} for t in rs_trades] + + diff_count = 0 + for pt in py_simple: + if pt not in rs_simple: + print(f"Python has trade not in Rust: {pt}") + diff_count += 1 + if diff_count > 10: + break + for rt in rs_simple: + if rt not in py_simple: + print(f"Rust has trade not in Python: {rt}") + diff_count += 1 + if diff_count > 20: + break - # 2. ๋”๋ฏธ ์บ”๋“ค 100๋งŒ ๊ฐœ ์ƒ์„ฑ (๋ถ€ํ•˜ ํ…Œ์ŠคํŠธ) - print("Generating 1,000,000 dummy candles in Python...") - start_time = time.time() - candles = [] - # ๋‹จ์ˆœ ํŒจํ„ด: RSI 30, ํฌ๊ฒŒ ๋–จ์–ด์ง€๊ณ (-4%), ๋ฐ˜๋“ฑ(2%)ํ•˜๋Š” ์บ”๋“ค 1๊ฐœ์™€ ๋‚˜๋จธ์ง€ ์ผ๋ฐ˜ ์บ”๋“ค - for i in range(1_000_000): - if i % 1000 == 0: - # ์ง„์ž… ์‹ ํ˜ธ ์กฐ๊ฑด ๋ถ€ํ•ฉํ•˜๋Š” ์บ”๋“ค - c = kis_rust_core.CandleData(f"2026-09-02 {i}", 1000.0, 1050.0, 960.0, 1020.0, 50000.0, 25.0) - elif i % 1000 == 5: - # ์ฒญ์‚ฐ(Target) ๋‹ฌ์„ฑํ•˜๋Š” ์บ”๋“ค (๊ณ ๊ฐ€ 1100 -> 10% ์ƒ์Šน) - c = kis_rust_core.CandleData(f"2026-09-02 {i}", 1020.0, 1100.0, 1010.0, 1080.0, 10000.0, 45.0) - else: - # ํ‰๋ฒ”ํ•œ ์บ”๋“ค - c = kis_rust_core.CandleData(f"2026-09-02 {i}", 1000.0, 1010.0, 990.0, 1000.0, 1000.0, 50.0) - candles.append(c) - print(f"Generated 1,000,000 objects in {time.time() - start_time:.3f}s") - - # 3. Rust ์—”์ง„์œผ๋กœ ๋˜์ง€๊ธฐ - print("Running Rust fast tail backtest...") - start_time = time.time() - pnl = kis_rust_core.run_tail_backtest_fast(params, candles) - elapsed = time.time() - start_time - - print(f"=====================================") - print(f"๐Ÿฆ€ RUST ENGINE RESULT:") - print(f"Total PnL: {pnl:.2f} โ‚ฉ") - print(f"Elapsed Time: {elapsed:.4f} seconds for 1M candles!") - print(f"=====================================") + if diff_count == 0: + print("100% Match!") + + finally: + db.close() if __name__ == "__main__": test_rust_tail() diff --git a/scratch/test_whip.py b/scratch/test_whip.py new file mode 100644 index 0000000..93e511a --- /dev/null +++ b/scratch/test_whip.py @@ -0,0 +1,13 @@ +import sys +sys.path.append("/home/hoon/kis_bot") +from kis_trader.backtest.optuna_web_jobs import _ob_whip_ui_from_params + +params = { + "whipsaw_enabled": True, + "whipsaw_filter_enabled": None, + "whipsaw_subbar_sec": 45, + "whipsaw_lookback_sec": 120, + "whipsaw_dip_pct": 0.001 +} +out = _ob_whip_ui_from_params(params) +print(out) diff --git a/scratch/verify_garbage_skip.py b/scratch/verify_garbage_skip.py new file mode 100644 index 0000000..23338f4 --- /dev/null +++ b/scratch/verify_garbage_skip.py @@ -0,0 +1,119 @@ +import sys +import os +import time +import datetime +from pathlib import Path + +ROOT = Path(__file__).resolve().parents[1] +sys.path.insert(0, str(ROOT)) + +from database import TradeDB +from kis_trader.engine.feed_fallback import packet_lag_seconds, is_feed_read_stale, bar_end_datetime, tick_in_bar_bucket + +def old_bar_is_garbage(ticks, candle_time, tf_min=1): + bucket = [] + for t in ticks: + raw = str(t.get("tick_time_raw") or t.get("tick_time") or "") + if tick_in_bar_bucket(str(raw), candle_time, tf_min): + bucket.append(t) + + if not bucket: + return True, "No ticks" + + bar_end = bar_end_datetime(candle_time, tf_min) + if bar_end is None: + return False, "No bar_end" + + stale_lags = [] + for t in bucket: + raw = str(t.get("tick_time_raw") or t.get("tick_time") or "") + lag = packet_lag_seconds(raw, now_dt=bar_end) + stale = is_feed_read_stale(lag) + if not stale: + return False, f"Valid tick lag: {lag:.2f}s" + stale_lags.append(lag) + + return True, f"All ticks stale relative to bar_end (min lag={min(stale_lags):.2f}s)" + +def main(): + db = TradeDB() + # ๋™๊ตญ์•Œ์•ค์—์Šค (323350) 2026-09-04 + code = "323350" + day = "20260904" + + print(f"[{code}] {day} ์บ”๋“ค ์กฐํšŒ ์ค‘...") + candles = db.conn.execute( + "SELECT * FROM ws_candles WHERE code=%s AND candle_time LIKE %s AND timeframe=1 ORDER BY candle_time ASC", + (code, f"{day}%%") + ).fetchall() + + candles = [dict(c) for c in candles] + print(f"์ด {len(candles)}๊ฐœ 1๋ถ„๋ด‰ ์บ”๋“ค ํ™•๋ณด.\n") + + print(f"[{code}] {day} ํ‹ฑ ์กฐํšŒ ์ค‘...") + ticks = db.conn.execute( + "SELECT * FROM ws_ticks WHERE code=%s AND tick_time LIKE %s ORDER BY tick_time ASC", + (code, f"{day}%%") + ).fetchall() + + ticks_dict = [] + for t in ticks: + ticks_dict.append({ + "tick_time": t["tick_time"], + "tick_time_raw": t["tick_time"], + "price": t["price"], + "volume": t["volume"] + }) + print(f"์ด {len(ticks_dict)}๊ฐœ ํ‹ฑ ํ™•๋ณด.\n") + + if not ticks_dict: + print("ํ‹ฑ ๋ฐ์ดํ„ฐ๊ฐ€ ์—†์–ด ๊ฒ€์ฆ์„ ์ข…๋ฃŒํ•ฉ๋‹ˆ๋‹ค.") + return + + garbage_count = 0 + valid_count = 0 + empty_count = 0 + + print("--- ๐Ÿ—‘๏ธ ๊ธฐ์กด ๋กœ์ง์— ์˜ํ•ด '์“ฐ๋ ˆ๊ธฐ(Garbage)'๋กœ ํŒ์ •๋œ ์ •์ƒ ์บ”๋“ค ์ƒ˜ํ”Œ ---\n") + + for c in candles: + # ws_candles๋Š” candle_time, ls_ws_candles๋Š” datetime ์ปฌ๋Ÿผ์„ ๊ฐ€์ง + ct = c.get("candle_time") or c.get("datetime") + if not ct: continue + bucket_ticks = [t for t in ticks_dict if tick_in_bar_bucket(t["tick_time"], ct, 1)] + + is_garbage, reason = old_bar_is_garbage(bucket_ticks, ct, 1) + + if len(bucket_ticks) == 0: + empty_count += 1 + continue + + if is_garbage: + garbage_count += 1 + if garbage_count <= 5: # 5๊ฐœ๋งŒ ์ƒ˜ํ”Œ ์ถœ๋ ฅ + vol = sum(t["volume"] for t in bucket_ticks) + last_tick_time = bucket_ticks[-1]["tick_time"] + bar_end_time = bar_end_datetime(ct, 1) + + print(f"[Garbage ์˜คํŒ] ์บ”๋“ค์‹œ๊ฐ„: {ct}") + print(f" -> ๋ถ„๋ด‰ ๋‚ด ์ฒด๊ฒฐ ํ‹ฑ ์ˆ˜: {len(bucket_ticks)}๊ฐœ") + print(f" -> ๋ถ„๋ด‰ ๋‚ด ๊ฑฐ๋ž˜๋Ÿ‰: {vol}์ฃผ") + print(f" -> ๋งˆ์ง€๋ง‰ ์ฒด๊ฒฐ ํ‹ฑ ์‹œ๊ฐ„: {last_tick_time}") + print(f" -> ๋ถ„๋ด‰ ์ข…๋ฃŒ ์ •๊ฐ ์‹œ๊ฐ„: {bar_end_time.strftime('%Y%m%d%H%M%S')}") + print(f" -> ํŒ์ • ์ด์œ : {reason}") + print(f" => ์ง„์งœ ์“ฐ๋ ˆ๊ธฐ? โŒ ์ •์ƒ ์บ”๋“ค์ธ๋ฐ ๋งˆ์ง€๋ง‰ ์ฒด๊ฒฐ์ด ์ •๊ฐ๋ณด๋‹ค ๋ช‡์ดˆ ์ผ์ฐ ๋๋‚ฌ์„ ๋ฟ์ž…๋‹ˆ๋‹ค.\n") + else: + valid_count += 1 + + print(f"=== ๐Ÿ“Š ์ตœ์ข… ๊ฒฐ๊ณผ ์š”์•ฝ ===") + print(f"์ด ์บ”๋“ค ์ˆ˜: {len(candles)}") + print(f"๊ฑฐ๋ž˜๊ฐ€ ์—†์—ˆ๋˜ ๋นˆ ์บ”๋“ค: {empty_count}") + print(f"์ •์ƒ ํŒ์ •(ํ†ต๊ณผ) ์บ”๋“ค: {valid_count}") + print(f"๊ฐ€๋น„์ง€๋กœ ์˜คํŒ(์‚ญ์ œ)๋œ ์บ”๋“ค: {garbage_count}") + + if (valid_count + garbage_count) > 0: + drop_rate = (garbage_count / (valid_count + garbage_count)) * 100 + print(f"๐Ÿš€ ๊ฑฐ๋ž˜๊ฐ€ ์žˆ์—ˆ๋˜ ์บ”๋“ค ์ค‘ ๋ฉ€์ฉกํ•œ๋ฐ ๋ฒ„๋ ค์ง„ ๋น„์œจ: {drop_rate:.1f}%") + +if __name__ == "__main__": + main() diff --git a/scratch_test_api.py b/scratch_test_api.py new file mode 100644 index 0000000..7a6cae8 --- /dev/null +++ b/scratch_test_api.py @@ -0,0 +1,12 @@ +import sys +sys.path.insert(0, '/home/hoon/kis_bot') +import backtest_web +with backtest_web.app.test_client() as c: + try: + resp = c.get('/api/env/params') + print(f"Status: {resp.status_code}") + if resp.status_code != 200: + print(resp.data.decode('utf-8')) + except Exception as e: + import traceback + traceback.print_exc() diff --git a/scripts/run_strategy_backtest_cli.py b/scripts/run_strategy_backtest_cli.py index ad849da..af8a464 100644 --- a/scripts/run_strategy_backtest_cli.py +++ b/scripts/run_strategy_backtest_cli.py @@ -154,7 +154,20 @@ def main() -> int: elif ob == "on": q["ob_filter"] = "1" + # Optuna ๋“ฑ์—์„œ ๋„˜์–ด์˜จ 1ํšŒ์„ฑ ํผ ํŒŒ๋ผ๋ฏธํ„ฐ(params_override JSON)๋ฅผ ์ฟผ๋ฆฌ์— ๋ณ‘ํ•ฉ + if args.params_json: + try: + with open(args.params_json, "r", encoding="utf-8") as f: + pj = json.load(f) + if isinstance(pj, dict): + for k, v in pj.items(): + if k not in q and v is not None and str(v) != "": + q[k] = str(v) + except Exception as e: + logger.warning("params_json ๋กœ๋“œ ์‹คํŒจ: %s", e) + qs = urlencode({k: str(v) for k, v in q.items() if v is not None and str(v) != ""}) + logger.info("๐Ÿ” [ํŒŒ๋ผ๋ฏธํ„ฐ ๋ณ‘ํ•ฉ ์™„๋ฃŒ] ์ฟผ๋ฆฌ์ŠคํŠธ๋ง: %s", qs) path, fn_name = _ROUTE[strat] _write_progress(prog_file, pct=20, phase="import", message="์›น๋ชจ๋“ˆ ๋กœ๋“œ") diff --git a/scripts/run_tail_backtest_cli.py b/scripts/run_tail_backtest_cli.py index d76640b..f344b8b 100755 --- a/scripts/run_tail_backtest_cli.py +++ b/scripts/run_tail_backtest_cli.py @@ -28,6 +28,15 @@ import json import logging import sys import time +import os + +# ๋ฐฑํ…Œ์ŠคํŠธ ์‹œ KIS/ํ‚ค์›€ ๋ฐ์ดํ„ฐ ์ถฉ๋Œ์— ์˜ํ•œ ์บ”๋“ค ๋ฒ„๋ฆผ ํ˜„์ƒ(Garbage skip) ๋ฐฉ์ง€ +os.environ["BACKTEST_CANDLE_GARBAGE_OFF"] = "1" +os.environ["CANDLE_GARBAGE_FALLBACK"] = "False" + +# ํŒŒ์ด์ฌ ์—”์ง„์—์„œ ์ดˆ๊ณ ์† Parquet ํ‹ฑ ๋กœ๋” ํ™œ์„ฑํ™” (breakout_tick_loader.py ์—ฐ๋™) +os.environ["BACKTEST_USE_RUST"] = "1" + from datetime import datetime from pathlib import Path from typing import Any, Dict, Optional diff --git a/static/js/backtest.js b/static/js/backtest.js index 99ca486..0d1cdba 100644 --- a/static/js/backtest.js +++ b/static/js/backtest.js @@ -206,6 +206,7 @@ function normalizeVirtualTrade(t, meta) { : (Number(t.is_mock) === 1 ? '๋ชจ์˜' : '์‹ค์ „') ), isMock: t.is_mock, + targetPrice: t.target_price, slippagePct: t.slippage_pct, }; } @@ -602,6 +603,8 @@ function renderVirtualTrades(tbodyId, trades, opts) { ${fmtPx(r.ep, rowFx)} ${exitPxCell} ${r.qty} + ${r.targetPrice != null ? fmtPx(r.targetPrice, rowFx) : '-'} + ${r.slippagePct != null ? `${r.slippagePct > 0 ? '+' : ''}${r.slippagePct.toFixed(3)}%` : '-'} ${pnlCell} ${fmtPct(r.rateNum)}`; if (opts.showCumulative) { @@ -2643,6 +2646,9 @@ function renderActual(d) { // ๋ŒํŒŒ ๋ฐฑํ…Œ์ŠคํŠธ ์‹คํ–‰ // โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ function runBreakoutBacktest() { + const useRust = document.querySelector('input[name="bt_engine_radio"]:checked')?.value === 'rust'; + const engineLabel = useRust ? '๐Ÿš€ [RUST ์—”์ง„]' : '๐Ÿ [PYTHON ์—”์ง„]'; + if (!confirm(`${engineLabel} ๋ฐฑํ…Œ์ŠคํŠธ๋ฅผ ์‹œ์ž‘ํ• ๊นŒ์š”?`)) return; let start = $('bo_start')?.value || ''; let end = $('bo_end')?.value || ''; if (!start) { @@ -2695,6 +2701,7 @@ function runBreakoutBacktest() { slot_money: $('bo_slot').value, max_stocks: $('bo_max_stocks')?.value || '20', total_budget_krw: $('bo_total_budget')?.value || '0', + use_spill_fallback: $('bo_use_spill_fallback')?.checked ? 1 : 0, universe: $('bo_use_univ_history')?.checked ? 'history' : 'all', universe_history_source: univHistorySourceParam('bo_univ_history_source'), candle_source: $('bo_candle_source')?.value || '', @@ -2766,6 +2773,7 @@ function saveBreakoutConfig() { slot_money: parseInt($('bo_slot').value, 10), max_stocks: parseInt($('bo_max_stocks')?.value || '20', 10), total_budget_krw: parseInt($('bo_total_budget')?.value || '0', 10), + use_spill_fallback: !!($('bo_use_spill_fallback')?.checked), ob_filter: !!($('bo_ob_filter')?.checked), pg_filter: !!($('bo_pg_filter')?.checked), daily_trail_tiers: ($('bo_daily_trail_tiers') && $('bo_daily_trail_tiers').value.trim()) || '', @@ -2917,6 +2925,9 @@ function renderBreakoutBacktest(d) { } function runRangeBreakBacktest() { + const useRust = document.querySelector('input[name="bt_engine_radio"]:checked')?.value === 'rust'; + const engineLabel = useRust ? '๐Ÿš€ [RUST ์—”์ง„]' : '๐Ÿ [PYTHON ์—”์ง„]'; + if (!confirm(`${engineLabel} ๋ฐฑํ…Œ์ŠคํŠธ๋ฅผ ์‹œ์ž‘ํ• ๊นŒ์š”?`)) return; let start = $('rb_start')?.value || ''; let end = $('rb_end')?.value || ''; if (!start) { @@ -3088,6 +3099,9 @@ function renderRangeBreakBacktest(d) { // - ํƒ์ƒ‰๊ฒฐ๊ณผ: /api/backtest/momentum/search_results ยท apply_search // ============================================================================ function runMomentumBacktest() { + const useRust = document.querySelector('input[name="bt_engine_radio"]:checked')?.value === 'rust'; + const engineLabel = useRust ? '๐Ÿš€ [RUST ์—”์ง„]' : '๐Ÿ [PYTHON ์—”์ง„]'; + if (!confirm(`${engineLabel} ๋ฐฑํ…Œ์ŠคํŠธ๋ฅผ ์‹œ์ž‘ํ• ๊นŒ์š”?`)) return; try { showSpinner(true); let start = $('mom_start')?.value || ''; @@ -3203,6 +3217,9 @@ function runMomentumBacktest() { /** ํ•ด์™ธ ๋ชจ๋ฉ˜ํ…€ ๋ฐฑํ…Œ โ€” /api/backtest/us_momentum (๊ตญ๋‚ด momentum API ๋ถ„๊ธฐ ์‚ฌ์šฉ ์•ˆ ํ•จ) */ function runUsMomentumBacktest() { + const useRust = document.querySelector('input[name="bt_engine_radio"]:checked')?.value === 'rust'; + const engineLabel = useRust ? '๐Ÿš€ [RUST ์—”์ง„]' : '๐Ÿ [PYTHON ์—”์ง„]'; + if (!confirm(`${engineLabel} ๋ฐฑํ…Œ์ŠคํŠธ๋ฅผ ์‹œ์ž‘ํ• ๊นŒ์š”?`)) return; try { showSpinner(true); let start = $('usmom_start')?.value || ''; @@ -3859,6 +3876,7 @@ async function usmomStockOptunaStart() { `์™„๋ฃŒ ํ›„ ใ€Œํผ์— ๋„ฃ๊ธฐใ€โ†’๋ฐฑํ…Œ ๊ฒ€์ฆ ยท ใ€Œ์ข…๋ชฉํ–‰์— ์ ์šฉใ€โ†’ stock_config\n(์ „์—ญ US_MOMENTUM_* ๋ฏธ์ ์šฉ)` )) return; try { + const useRust = document.querySelector('input[name="bt_engine_radio"]:checked')?.value === 'rust'; const r = await fetch('/api/optuna/start', { method: 'POST', headers: { 'Content-Type': 'application/json' }, @@ -3870,6 +3888,7 @@ async function usmomStockOptunaStart() { candle_source: candleSrc, tick_source: tickSrc, ob_source: obSrc, + use_rust: useRust, }), }); const j = await r.json(); @@ -4623,7 +4642,9 @@ function fillObWhipReadonly(prefix, s) { : (s.min_bid_ask_ratio != null ? s.min_bid_ask_ratio : s.orderbook_min_bid_ask_ratio); const ask = s.ob_ask_max_mult != null ? s.ob_ask_max_mult : (s.ask_max_mult != null ? s.ask_max_mult : s.orderbook_entry_ask_max_mult); - const whipOn = s.whipsaw_filter_enabled != null ? s.whipsaw_filter_enabled : s.whipsaw_enabled; + let whipOn = false; + if (s.whipsaw_filter_enabled != null) whipOn = s.whipsaw_filter_enabled; + else if (s.whipsaw_enabled != null) whipOn = s.whipsaw_enabled; on(`${p}_ob_ro_on`, obOn); num(`${p}_ob_ro_spread`, spread); num(`${p}_ob_ro_ratio`, ratio); @@ -4657,13 +4678,26 @@ function optunaObWhipOverridesFromParams(p) { if (!p || typeof p !== 'object') return {}; const obOn = p.ob_filter_enabled != null ? p.ob_filter_enabled : p._orderbook_filter_enabled; const pgOn = p.pg_filter_enabled != null ? p.pg_filter_enabled : p._program_filter_enabled; - const whipOn = p.whipsaw_filter_enabled != null ? p.whipsaw_filter_enabled : p.whipsaw_enabled; + let whipOn = false; + if (p.whipsaw_filter_enabled != null) whipOn = p.whipsaw_filter_enabled; + else if (p.whipsaw_enabled != null) whipOn = p.whipsaw_enabled; const spread = p.max_spread_pct != null ? p.max_spread_pct : p._ob_max_spread_pct; const ratio = p.ob_min_bid_ask_ratio != null ? p.ob_min_bid_ask_ratio : (p.min_bid_ask_ratio != null ? p.min_bid_ask_ratio : p._ob_min_bid_ask_ratio); const ask = p.ob_ask_max_mult != null ? p.ob_ask_max_mult : (p.ask_max_mult != null ? p.ask_max_mult : p._ob_ask_max_mult); + const out = {}; + + // 1. Optuna ํŒŒ๋ผ๋ฏธํ„ฐ ์ค‘ ๋‚ ์งœ/์œ ๋‹ˆ๋ฒ„์Šค ๋“ฑ ํผ ๋ฉ”ํƒ€ ์ •๋ณด๋Š” ์ œ์™ธํ•˜๊ณ  ๋ชจ๋‘ ๋ณต์‚ฌ (์†์ ˆ, ์ต์ ˆ ๋“ฑ 1ํšŒ์„ฑ ์ ์šฉ ๋ณด์žฅ) + const excludeKeys = ['start', 'end', 'universe', 'candle_source', 'tick_source', 'ob_source', 'universe_history_source', 'strategy', 'market']; + for (const k in p) { + if (!excludeKeys.includes(k)) { + out[k] = p[k]; + } + } + + // 2. ํ˜ธ๊ฐ€/ํœฉ์˜ ๋“ฑ ๋ช…์นญ์ด ๋‹ค๋ฅธ ๊ฒƒ๋“ค์„ ๋ฐฑํ…Œ API ์ŠคํŽ™์— ๋งž๊ฒŒ ๋ช…ํ™•ํžˆ ๋งคํ•‘ (๊ธฐ์กด ๋กœ์ง) if (obOn != null) out.ob_filter = obOn ? 1 : 0; if (pgOn != null) out.pg_filter = pgOn ? 1 : 0; if (spread != null && spread !== '') out.max_spread_pct = spread; @@ -4674,17 +4708,26 @@ function optunaObWhipOverridesFromParams(p) { if (p.whipsaw_lookback_sec != null) out.whipsaw_lookback_sec = p.whipsaw_lookback_sec; if (p.whipsaw_dip_pct != null) out.whipsaw_dip_pct = p.whipsaw_dip_pct; if (p.whipsaw_recovery_tol_pct != null) out.whipsaw_recovery_tol_pct = p.whipsaw_recovery_tol_pct; + + // boolean ์ฒ˜๋ฆฌ๊ฐ€ ํ•„์š”ํ•œ ํ”Œ๋ž˜๊ทธ ๊ฐ’๋“ค์€ 1/0์œผ๋กœ ๋ณ€ํ™˜ (์ฒดํฌ๋ฐ•์Šค ์˜ค๋ฒ„๋ผ์ด๋“œ์šฉ) + if (p.use_defense_filters === true || p.use_defense_filters === false) out.use_defense_filters = p.use_defense_filters ? 1 : 0; + if (p.use_macd_cross === true || p.use_macd_cross === false) out.use_macd_cross = p.use_macd_cross ? 1 : 0; + if (p.require_reversal_candle === true || p.require_reversal_candle === false) out.require_reversal_candle = p.require_reversal_candle ? 1 : 0; + if (p.skip_hts_scan_dupes === true || p.skip_hts_scan_dupes === false) out.skip_hts_scan_dupes = p.skip_hts_scan_dupes ? 1 : 0; + return out; } function mergeOptunaObWhipQuery(params) { - const ov = optunaObWhipOverridesFromHidden('tl'); - if (!ov || !Object.keys(ov).length) { - const mem = window._optunaBacktestObWhipOverrides; - if (!mem || typeof mem !== 'object' || !Object.keys(mem).length) return params; + const mem = window._optunaBacktestObWhipOverrides; + if (mem && typeof mem === 'object' && Object.keys(mem).length > 0) { return Object.assign({}, params, mem); } - return Object.assign({}, params, ov); + const ov = optunaObWhipOverridesFromHidden('tl'); + if (ov && Object.keys(ov).length > 0) { + return Object.assign({}, params, ov); + } + return params; } function optunaObWhipOverridesFromHidden(prefix) { @@ -4733,7 +4776,9 @@ function applyOptunaObWhipToHiddenInputs(p, prefix) { }[px]; if (!hid) return; const set = (id, v) => { if ($(id) && v !== undefined && v !== null && v !== '') $(id).value = v; }; - const whipOn = p.whipsaw_filter_enabled != null ? p.whipsaw_filter_enabled : p.whipsaw_enabled; + let whipOn = false; + if (p.whipsaw_filter_enabled != null) whipOn = p.whipsaw_filter_enabled; + else if (p.whipsaw_enabled != null) whipOn = p.whipsaw_enabled; if (whipOn != null) set(hid.whip, whipOn ? '1' : '0'); set(hid.sub, p.whipsaw_subbar_sec); set(hid.lb, p.whipsaw_lookback_sec); @@ -5622,7 +5667,7 @@ function envTimelineParam(checkboxId) { return $(checkboxId)?.checked ? 1 : 0; } -function runBacktest() { +function collectScalpBacktestFormParams() { const params = { start: $('bt_start').value, end: $('bt_end').value, @@ -5650,6 +5695,7 @@ function runBacktest() { use_macd_cross: $('bt_use_macd')?.checked ? 1 : 0, skip_hts_scan_dupes: $('bt_skip_hts_dupes')?.checked ? 1 : 0, require_reversal_candle: $('bt_require_reversal')?.checked ? 1 : 0, + use_spill_fallback: $('bt_use_spill_fallback')?.checked ? 1 : 0, max_stocks: $('bt_max_stocks')?.value, total_budget_krw: $('bt_total_budget')?.value, eod_enabled: $('bt_eod_enabled')?.checked ? 1 : 0, @@ -5661,6 +5707,14 @@ function runBacktest() { params.candle_source = $('bt_candle_source')?.value || ''; params.tick_source = $('bt_tick_source')?.value || ''; params.ob_source = $('bt_ob_source')?.value || ''; + return params; +} + +function runBacktest() { + const useRust = document.querySelector('input[name="bt_engine_radio"]:checked')?.value === 'rust'; + const engineLabel = useRust ? '๐Ÿš€ [RUST ์—”์ง„]' : '๐Ÿ [PYTHON ์—”์ง„]'; + if (!confirm(`${engineLabel} ๋ฐฑํ…Œ์ŠคํŠธ๋ฅผ ์‹œ์ž‘ํ• ๊นŒ์š”?`)) return; + const params = collectScalpBacktestFormParams(); const qs = new URLSearchParams(mergeOptunaObWhipQuery(params)).toString(); showSpinner(true); fetch('/api/backtest/scalping?' + qs) @@ -6402,6 +6456,9 @@ function collectTailBacktestFormParams() { } function runTailBacktest() { + const useRust = document.querySelector('input[name="bt_engine_radio"]:checked')?.value === 'rust'; + const engineLabel = useRust ? '๐Ÿš€ [RUST ์—”์ง„]' : '๐Ÿ [PYTHON ์—”์ง„]'; + if (!confirm(`${engineLabel} ๋ฐฑํ…Œ์ŠคํŠธ๋ฅผ ์‹œ์ž‘ํ• ๊นŒ์š”?`)) return; const params = collectTailBacktestFormParams(); const qs = new URLSearchParams(mergeOptunaObWhipQuery(params)).toString(); showSpinner(true); @@ -6438,7 +6495,7 @@ const BTJOB_CFG = { tab: 'backtest', label: '์Šค์บ˜ํ•‘ ๋ฐฑํ…Œ', startId: 'bt_start', endId: 'bt_end', tfId: null, - univId: 'bt_use_univ_history', univSrcId: 'bt_univ_history_source', tickId: null, + univId: 'bt_use_univ_history', univSrcId: 'bt_univ_history_source', tickId: null, spillId: 'bt_use_spill_fallback', envId: 'bt_env_timeline', obId: null, stopBtn: 'bt_btn_stop_bg', tabFill: 'scalp_bt_tab_fill', tabStatus: 'scalp_bt_tab_status', clearPrefix: 'b_', @@ -6448,7 +6505,7 @@ const BTJOB_CFG = { tab: 'breakout', label: '๋ŒํŒŒ ๋ฐฑํ…Œ', startId: 'bo_start', endId: 'bo_end', tfId: null, - univId: 'bo_use_univ_history', univSrcId: 'bo_univ_history_source', tickId: null, + univId: 'bo_use_univ_history', univSrcId: 'bo_univ_history_source', tickId: null, spillId: 'bo_use_spill_fallback', envId: 'bo_env_timeline', obId: null, stopBtn: 'bo_btn_stop_bg', tabFill: 'bo_bt_tab_fill', tabStatus: 'bo_bt_tab_status', clearPrefix: 'bo_', @@ -6458,7 +6515,7 @@ const BTJOB_CFG = { tab: 'momentum', label: '๋ชจ๋ฉ˜ํ…€ ๋ฐฑํ…Œ', startId: 'mom_start', endId: 'mom_end', tfId: null, - univId: 'mom_use_univ_history', univSrcId: 'mom_univ_history_source', tickId: null, + univId: 'mom_use_univ_history', univSrcId: 'mom_univ_history_source', tickId: null, spillId: 'mom_use_spill_fallback', envId: 'mom_env_timeline', obId: 'mom_ob_filter', stopBtn: 'mom_btn_stop_bg', tabFill: 'mom_bt_tab_fill', tabStatus: 'mom_bt_tab_status', clearPrefix: 'mom_', @@ -6543,11 +6600,24 @@ function btJobSetNav(job) { const stEl = cfg.tabStatus && $(cfg.tabStatus); if (stEl) { const msg = prog.message || ''; + const logId = 'bt_log_pre_' + strat; + let isAtBottom = false; + const oldPre = stEl.querySelector('#' + logId); + if (oldPre) { + isAtBottom = (oldPre.scrollHeight - oldPre.scrollTop <= oldPre.clientHeight + 20); + } else { + isAtBottom = true; + } stEl.innerHTML = `${st} ${pct}%` + range + (msg ? ` ยท ${msg}` : '') + (job.log_path ? ` ยท ${job.log_path}` : '') + - ' ยท ์ „์—ญ 1์žก ยท ํƒญ ์ด๋™ OK'; + ' ยท ์ „์—ญ 1์žก ยท ํƒญ ์ด๋™ OK' + + (job.log_tail ? `
${job.log_tail}
` : ''); + const newPre = stEl.querySelector('#' + logId); + if (newPre && isAtBottom) { + newPre.scrollTop = newPre.scrollHeight; + } } // ๋ชจ๋“  ์ „๋žต ์ค‘์ง€ ๋ฒ„ํŠผ ๋™๊ธฐํ™” Object.values(BTJOB_CFG).forEach(c => { @@ -6651,8 +6721,11 @@ function btJobCollectBody(strategy) { }; if (cfg.tfId && $(cfg.tfId)) body.timeframe = $(cfg.tfId).value || 3; if (cfg.tickId) body.backtest_use_tick_db = $(cfg.tickId)?.checked !== false ? 1 : 0; + if (cfg.spillId) body.backtest_use_spill_fallback = $(cfg.spillId)?.checked !== false ? 1 : 0; if (strategy === 'tail') { - body.form_params = collectTailBacktestFormParams(); + body.form_params = mergeOptunaObWhipQuery(collectTailBacktestFormParams()); + } else if (strategy === 'scalp') { + body.form_params = mergeOptunaObWhipQuery(collectScalpBacktestFormParams()); } const rustRadio = document.querySelector('input[name="bt_engine_radio"]:checked'); @@ -6672,8 +6745,9 @@ async function btJobStart(strategy) { const whipHint = strategy === 'tail' && $('tl_h_whipsaw_filter')?.value !== '' ? `\nํœฉ์˜ hidden=${$('tl_h_whipsaw_filter').value === '1' ? 'ON' : 'OFF'}` : ''; + const engineLabel = body.use_rust ? '๐Ÿš€ [RUST ์—”์ง„]' : '๐Ÿ [PYTHON ์—”์ง„]'; if (!confirm( - `${BTJOB_CFG[strategy].label} ๋ฐฑ๊ทธ๋ผ์šด๋“œ ์‹œ์ž‘?\n${body.start}~${body.end}\n` + + `${engineLabel}\n${BTJOB_CFG[strategy].label} ๋ฐฑ๊ทธ๋ผ์šด๋“œ ์‹œ์ž‘?\n${body.start}~${body.end}\n` + (hasForm ? `ํŒŒ๋ผ๋ฏธํ„ฐ=ํ˜„์žฌ ํผ(+Optuna hidden ํ˜ธ๊ฐ€/ํœฉ์˜)${whipHint}` : `ํŒŒ๋ผ๋ฏธํ„ฐ=ํ˜„์žฌ DB (+๊ธฐ๊ฐ„/์œ ๋‹ˆ๋ฒ„์Šค)`) + @@ -8678,6 +8752,7 @@ function optunaRenderModeCombo(sum) { (sum ? 'mode_combo ์‹ค์ธก ์—†์Œ (๊ตฌ JSONยท๋ฏธ์‚ฐ์ถœ)' : '์™„๋ฃŒ ํ›„ ํ‘œ์‹œ'), + window._optunaGlobalDbParams ); if (!el) return; if (!m || !m.ok) { @@ -8728,6 +8803,7 @@ function optunaRenderModeTop10(sum) { (sum && sum.top5_consensus) || [], 'consensus', sum ? 'mode Top10 ์—†์Œ (pool 0 ยท grid/results ํ™•์ธ)' : '์™„๋ฃŒ ํ›„ ํ‘œ์‹œ', + window._optunaGlobalDbParams ); optunaRenderModeBandTop3(sum, window._optunaLastJob || null); } @@ -8753,7 +8829,7 @@ function optunaDailyAvgPctCell(r) { return `${sign}${optunaFmtNum(n, 3)}%`; } -function optunaModeTopTableRow(r, source) { +function optunaModeTopTableRow(r, source, dbData) { const rank = r.rank || 1; const src = source; const applyCls = 'btn-outline-success'; @@ -8773,7 +8849,7 @@ function optunaModeTopTableRow(r, source) { ${optunaFmtNum(r.total_pnl)} ${optunaDailyAvgPnlCell(r)} ${optunaDailyAvgPctCell(r)} - ${optunaObWhipCell(r)} + ${optunaObWhipCell(r, null, dbData)} ${r.n_losing_days != null ? optunaFmtNum(r.n_losing_days, 0) : 'โ€”'} ${r.worst_day_pnl != null ? optunaFmtNum(r.worst_day_pnl) : 'โ€”'} ${optunaStableScoreCell(r)} @@ -8785,14 +8861,14 @@ function optunaModeTopTableRow(r, source) { `; } -function optunaFillModeTopTbody(tbodyId, rows, source, emptyMsg) { +function optunaFillModeTopTbody(tbodyId, rows, source, emptyMsg, dbData) { const tb = $(tbodyId); if (!tb) return; if (!rows || !rows.length) { tb.innerHTML = `${emptyMsg}`; return; } - tb.innerHTML = rows.map((r) => optunaModeTopTableRow(r, source)).join(''); + tb.innerHTML = rows.map((r) => optunaModeTopTableRow(r, source, dbData)).join(''); } function optunaRenderOverfit(sum) { @@ -9063,7 +9139,7 @@ function optunaRenderParamDistChart(sum) { ํŒŒ๋ž€ ๋  = p25 ~ p75 ๊ตฌ๊ฐ„ (์ƒ์œ„ํ•ฉ๊ฒฉ trial ์ค‘ ์ค‘๊ฐ„ 50% ยท IQR)
๋…น์ƒ‰ ์„  = median (์ค‘์•™๊ฐ’ ยท ํ•ฉ๊ฒฉ trial ์ค‘ ๋”ฑ 50๋ฒˆ์งธ ๋ฐฑ๋ถ„์œ„)
์ฃผํ™ฉ ์  = mode (์ตœ๋นˆ๊ฐ’ ยท DB ์ ์šฉ ํ›„๋ณด์—์„œ ๊ฐ€์žฅ ๋งŽ์ด ์„ ํƒ๋œ ๊ฐ’)
- ๏ฟฝ๏ฟฝ ์ฃผํ™ฉ(mode)๊ณผ ๋…น์ƒ‰(median)์ด ๊ฐ€๊นŒ์šธ์ˆ˜๋ก ๋ถ„ํฌ๊ฐ€ ์•ˆ์ •์ . ํŒŒ๋ž€๋ ๊ฐ€ ๋„“์œผ๋ฉด ํŒŒ๋ผ๋ฏธํ„ฐ ์„ ํƒ ํญ์ด ํผ. ๋…น์ƒ‰์ด ์ค‘์•™์—์„œ ์น˜์šฐ์น˜๋Š” ๊ฑด ๋ถ„ํฌ๊ฐ€ ํ•œ์ชฝ์œผ๋กœ ๋ชฐ๋ฆฐ ๋น„๋Œ€์นญ(skew) ๋•Œ๋ฌธ. + ์ฃผํ™ฉ(mode)๊ณผ ๋…น์ƒ‰(median)์ด ๊ฐ€๊นŒ์šธ์ˆ˜๋ก ๋ถ„ํฌ๊ฐ€ ์•ˆ์ •์ . ํŒŒ๋ž€๋ ๊ฐ€ ๋„“์œผ๋ฉด ํŒŒ๋ผ๋ฏธํ„ฐ ์„ ํƒ ํญ์ด ํผ. ๋…น์ƒ‰์ด ์ค‘์•™์—์„œ ์น˜์šฐ์น˜๋Š” ๊ฑด ๋ถ„ํฌ๊ฐ€ ํ•œ์ชฝ์œผ๋กœ ๋ชฐ๋ฆฐ ๋น„๋Œ€์นญ(skew) ๋•Œ๋ฌธ. `; const bars = rows.map((r) => { const p25 = Number(r.p25); @@ -9156,20 +9232,39 @@ function optunaPostBusy(job) { return job.status === 'running' && Number(prog.pct || 0) >= 99.9; } -function formatWhipParam(vRaw, prefix, suffix, dec, statKey, stats, scale100) { +function formatWhipParam(vRaw, prefix, suffix, dec, statKey, stats, scale100, dbData) { if (vRaw == null) return null; let v = Number(vRaw); if (scale100 && v < 0.5) v *= 100; let text = `${prefix}${v.toFixed(dec)}${suffix}`; - if (!stats || !stats[statKey]) return text; + + let dbStyle = ''; + if (dbData && dbData[statKey] != null) { + let dbV = Number(dbData[statKey]); + if (scale100 && dbV < 0.5) dbV *= 100; + const diff = Math.abs(v - dbV); + const base = Math.max(Math.abs(dbV), 0.0001); + const diffRatio = diff / base; + if (diffRatio < 0.05 || diff < 0.0001) { + dbStyle = 'border-bottom: 2px solid #3fb950;'; // 5% ์ด๋‚ด: ๋…น์ƒ‰ (๋งค์šฐ ์œ ์‚ฌ) + } else if (diffRatio < 0.2) { + dbStyle = 'border-bottom: 2px solid #f0883e;'; // 20% ์ด๋‚ด: ์ฃผํ™ฉ์ƒ‰ (๋น„์Šทํ•จ) + } else { + dbStyle = 'border-bottom: 2px solid transparent;'; // ๊ทธ ์ด์ƒ ์ฐจ์ด + } + } + + if (!stats || !stats[statKey]) { + return `${text}`; + } const s = stats[statKey]; const dist = Math.abs(v - s.avg); const ratio = s.maxDist > 0 ? 1 - (dist / s.maxDist) : 1; const alpha = Math.round((0.2 + (0.8 * ratio)) * 100); - return `${text}`; + return `${text}`; } -function optunaObWhipCell(r, stats) { +function optunaObWhipCell(r, stats, dbData) { if (!r) return 'โ€”'; const on = r.ob_on; const whip = r.whip_on; @@ -9184,9 +9279,9 @@ function optunaObWhipCell(r, stats) { const lines = []; if (on === true) { const bits = ['ํ˜ธ๊ฐ€ON']; - if (r.ob_spread != null) bits.push(formatWhipParam(r.ob_spread, 'spr', '', 1, 'ob_spread', stats)); - if (r.ob_ratio != null) bits.push(formatWhipParam(r.ob_ratio, 'r', '', 2, 'ob_ratio', stats)); - if (r.ob_ask != null) bits.push(formatWhipParam(r.ob_ask, 'askร—', '', 0, 'ob_ask', stats)); + if (r.ob_spread != null) bits.push(formatWhipParam(r.ob_spread, 'spr', '', 1, 'ob_spread', stats, false, dbData)); + if (r.ob_ratio != null) bits.push(formatWhipParam(r.ob_ratio, 'r', '', 2, 'stop_ob_ratio_min', stats, false, dbData)); + if (r.ob_ask != null) bits.push(formatWhipParam(r.ob_ask, 'askร—', '', 0, 'ob_ask', stats, false, dbData)); lines.push(`
${bits.join(' ')}
`); } else if (on === false) { lines.push('
ํ˜ธ๊ฐ€OFF
'); @@ -9194,18 +9289,18 @@ function optunaObWhipCell(r, stats) { if (hasExit) { const eb = []; - if (r.tp_pct != null) eb.push(formatWhipParam(r.tp_pct, '์ต์ ˆ', '%', 1, 'tp_pct', stats)); - if (r.tp_max_pct != null) eb.push(formatWhipParam(r.tp_max_pct, '์ƒํ•œ', '%', 1, 'tp_max_pct', stats)); - if (r.sl_pct != null) eb.push(formatWhipParam(r.sl_pct, '์†์ ˆ', '%', 1, 'sl_pct', stats)); + if (r.tp_pct != null) eb.push(formatWhipParam(r.tp_pct, '์ต์ ˆ', '%', 1, 'tp_pct', stats, false, dbData)); + if (r.tp_max_pct != null) eb.push(formatWhipParam(r.tp_max_pct, '์ƒํ•œ', '%', 1, 'tp_max_pct', stats, false, dbData)); + if (r.sl_pct != null) eb.push(formatWhipParam(r.sl_pct, '์†์ ˆ', '%', 1, 'sl_pct', stats, false, dbData)); lines.push(`
${eb.join(' ')}
`); } if (whip === true) { const wb = ['ํœฉ์˜ON']; - if (r.whip_subbar_sec != null) wb.push(formatWhipParam(r.whip_subbar_sec, 'sub', 's', 0, 'whip_subbar_sec', stats)); - if (r.whip_lookback_sec != null) wb.push(formatWhipParam(r.whip_lookback_sec, 'lb', 's', 0, 'whip_lookback_sec', stats)); - if (r.whip_dip_pct != null) wb.push(formatWhipParam(r.whip_dip_pct, 'dip', '%', 2, 'whip_dip_pct', stats, true)); - if (r.whip_recovery_tol_pct != null) wb.push(formatWhipParam(r.whip_recovery_tol_pct, 'tol', '%', 2, 'whip_recovery_tol_pct', stats, true)); + if (r.whip_subbar_sec != null) wb.push(formatWhipParam(r.whip_subbar_sec, 'sub', 's', 0, 'whipsaw_subbar_sec', stats, false, dbData)); + if (r.whip_lookback_sec != null) wb.push(formatWhipParam(r.whip_lookback_sec, 'lb', 's', 0, 'whipsaw_lookback_sec', stats, false, dbData)); + if (r.whip_dip_pct != null) wb.push(formatWhipParam(r.whip_dip_pct, 'dip', '%', 2, 'whipsaw_dip_pct', stats, true, dbData)); + if (r.whip_recovery_tol_pct != null) wb.push(formatWhipParam(r.whip_recovery_tol_pct, 'tol', '%', 2, 'whipsaw_tol', stats, true, dbData)); lines.push(`
${wb.join(' ')}
`); } else if (whip === false && (on != null || hasExit)) { lines.push('
ํœฉ์˜OFF
'); @@ -9217,7 +9312,7 @@ function optunaObWhipCell(r, stats) { return `
${lines.join('')}
`; } -function optunaRankTableRow(r, source) { +function optunaRankTableRow(r, source, dbData) { const rank = r.rank || 1; const src = source; const detailBtn = ''; @@ -9231,7 +9326,7 @@ function optunaRankTableRow(r, source) { ${optunaFmtNum(r.total_pnl)} ${optunaDailyAvgPnlCell(r)} ${optunaDailyAvgPctCell(r)} - ${optunaObWhipCell(r)} + ${optunaObWhipCell(r, null, dbData)} ${r.n_losing_days != null ? optunaFmtNum(r.n_losing_days, 0) : 'โ€”'} ${r.worst_day_pnl != null ? optunaFmtNum(r.worst_day_pnl) : 'โ€”'} ${optunaStableScoreCell(r)} @@ -9245,14 +9340,14 @@ function optunaRankTableRow(r, source) { `; } -function optunaFillRankTbody(tbodyId, rows, source, emptyMsg) { +function optunaFillRankTbody(tbodyId, rows, source, emptyMsg, dbData) { const tb = $(tbodyId); if (!tb) return; if (!rows || !rows.length) { tb.innerHTML = `${emptyMsg}`; return; } - tb.innerHTML = rows.map((r) => optunaRankTableRow(r, source)).join(''); + tb.innerHTML = rows.map((r) => optunaRankTableRow(r, source, dbData)).join(''); } /** Optuna ํ›„์ฒ˜๋ฆฌ ํ‘œ โ€” ํ–‰=gated# / mode / live, ์—ด=ํ˜ธ๊ฐ€ยทํœฉ์˜ยทํŠธ๋ ˆ์ผ (์› ์ •์ˆ˜). */ @@ -10004,7 +10099,7 @@ function optunaRenderJob(job) { } $('opt_st_top').innerHTML = html; window._optunaLastSummary = { top5_learn: ls.top3_learn || [], n_all: ls.n_complete }; - optunaRenderTop5(window._optunaLastSummary); + optunaRenderTop5(window._optunaLastSummary, window._optunaGlobalDbParams); } else if (sum && sum.top) { const t = sum.top; const dAvg = (t.period_daily_avg_pnl != null) @@ -10107,7 +10202,9 @@ async function optunaBacktestFromCandidate(source, rank) { }; const cache = window._optunaCandidateCache; const strat = String(cache.strategy || curJob?.strategy || '').toLowerCase(); - const p = cache.params || {}; + const pTune = cache.params || {}; + const pEng = cache.params_engine || {}; + const p = Object.assign({}, pEng, pTune); window._optunaBacktestObWhipOverrides = optunaObWhipOverridesFromParams(p); applyOptunaObWhipToHiddenInputs(p, strat === 'tail' ? 'tl' : (strat === 'scalp' ? 'bt' : 'tl')); const job = curJob || {}; @@ -10132,6 +10229,14 @@ async function optunaBacktestFromCandidate(source, rank) { if (job.ob_source && cfg.obId && $(cfg.obId)) { $(cfg.obId).value = job.ob_source; } + if (p.use_rust !== undefined) { + const radList = document.querySelectorAll('input[name="bt_engine_radio"]'); + radList.forEach(r => { + if ((p.use_rust && r.value === 'rust') || (!p.use_rust && r.value === 'python')) { + r.checked = true; + } + }); + } }; const tabMap = { @@ -10246,6 +10351,7 @@ function fillTailFormFromOptunaParams(p) { function fillScalpFormFromOptunaParams(p) { if (!p || typeof p !== 'object') return; fillScalpFormFromApi(p); + applyOptunaObWhipToEditableForm(p, 'bt'); if (typeof fillObWhipReadonly === 'function') fillObWhipReadonly('bt', p); } @@ -10256,7 +10362,7 @@ async function optunaFillFormFromCandidate(source, rank) { await optunaShowCandidate(source || 'gated', rank || 1); cache = window._optunaCandidateCache; } - const p = (cache && cache.params) || {}; + const p = Object.assign({}, cache.merged_params || cache.params || {}); const strat = String((cache && cache.strategy) || '').toLowerCase(); const isUs = strat === 'us_momentum' || String(p.market || '').toUpperCase() === 'US'; const set = (id, val) => { @@ -10672,7 +10778,7 @@ function optunaBreakoutObModes() { return out.length ? out : ['off']; } -async function optunaStart() { +async function optunaStart(forceRust = null) { const strategies = optunaSelectedStrategies(); const start = $('opt_start')?.value; const end = $('opt_end')?.value; @@ -10715,7 +10821,9 @@ async function optunaStart() { const chainLabel = needSeq ? `\n๊ฐ ์ „๋žต/์กฐํ•ฉ: 1์ฐจ(๋„“์€ Grid) โ†’ 2์ฐจ(๋ฐด๋“œ ์ถ•์†Œ) ํ›„ ๋‹ค์Œ` : `\n1ยท2์ฐจ TPE ์—ฐ์‡„ (1์ฐจ ๋„“์€ Grid โ†’ 2์ฐจ ๋ฐด๋“œ ์ถ•์†Œ)`; - if (!confirm(`Optuna ์‹œ์ž‘?\n${how}: ${strategies.join(', ')}\n${start}~${end} trials=${trials}` + + const useRust = forceRust !== null ? forceRust : (document.querySelector('input[name="bt_engine_radio"]:checked')?.value === 'rust'); + const engineLabel = useRust ? '๐Ÿš€ [RUST ์—”์ง„]' : '๐Ÿ [PYTHON ์—”์ง„]'; + if (!confirm(`${engineLabel}\nOptuna ์‹œ์ž‘?\n${how}: ${strategies.join(', ')}\n${start}~${end} trials=${trials}` + (studyTrials ? `\n์Šคํ„ฐ๋”” ์ด ํšŸ์ˆ˜=${studyTrials}` : '') + `${chainLabel}\n์Šน๋ฆฌ์‹=${sortLabel}\n์ด๋ ฅ์†Œ์Šค=${srcLabel}${emLabel}${slLabel}\n(DB ๋ฏธ์ ์šฉ)`)) return; try { @@ -10734,6 +10842,7 @@ async function optunaStart() { entry_modes: strategies.includes('tail') ? entryModes : undefined, sl_modes: strategies.includes('breakout') ? slModes : undefined, ob_modes: strategies.includes('breakout') ? obModes : undefined, + use_rust: useRust, }), }); const j = await r.json(); @@ -10900,6 +11009,8 @@ async function optunaRefreshJobs() { if (job.breakout_sl_modes) runParams.push('๋ŒํŒŒ์†์ ˆ:' + job.breakout_sl_modes); if (job.breakout_ob_modes) runParams.push('๋ŒํŒŒํ˜ธ๊ฐ€:' + job.breakout_ob_modes); + const engineLabel = job.engine_label ? ` ${job.engine_label}` : ''; + const paramsDiv = runParams.length > 0 ? `
${runParams.join(' ยท ')}
` : ''; return ` @@ -10907,7 +11018,7 @@ async function optunaRefreshJobs() { ${jid} - ${label}${studyNote}${paramsDiv} + ${label}${engineLabel}${studyNote}${paramsDiv} ${optunaFormatJobPeriodCell(job)} ${stCell}${job.phase === 'postprocess' ? ' ยทํ›„์ฒ˜๋ฆฌ' : ''}${statusNote} ${(() => { @@ -11270,15 +11381,19 @@ async function compareSelectedJobs() { optCmpModalInst.show(); try { - const jobData = []; - // ํ•ญ์ƒ topn API ํ˜ธ์ถœ (๋ฆฌ์ŠคํŠธ API์—๋Š” top5_gated๊ฐ€ ์—†๊ธฐ ๋•Œ๋ฌธ) - for (const jid of jobIds) { + // ํ•ญ์ƒ topn API ํ˜ธ์ถœ (๋ฆฌ์ŠคํŠธ API์—๋Š” top5_gated๊ฐ€ ์—†๊ธฐ ๋•Œ๋ฌธ) - Promise.all๋กœ ๋ณ‘๋ ฌ ์ฒ˜๋ฆฌํ•˜์—ฌ ์†๋„ ๊ฐœ์„  + const fetchPromises = jobIds.map(async (jid) => { try { const r = await fetch('/api/optuna/topn/' + encodeURIComponent(jid), {signal: AbortSignal.timeout(5000)}); const j2 = await r.json(); - if (j2.ok) jobData.push(j2); + if (j2.ok) return j2; } catch(e) { console.warn('topn fetch failed for', jid, e); } - } + return null; + }); + + const results = await Promise.all(fetchPromises); + const jobData = results.filter(j2 => j2 !== null); + if (!jobData.length) { document.getElementById('optCmpTableWrap').innerHTML = '
๋ถˆ๋Ÿฌ์˜จ ํ•ญ๋ชฉ ๋ฐ์ดํ„ฐ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.
'; return; @@ -11290,12 +11405,21 @@ async function compareSelectedJobs() { // Header let html = ''; - html += ''; + html += ''; + + // DB ๋ฐ์ดํ„ฐ ๋กœ๋“œ + let dbParams = {}; + try { + const rDb = await fetch('/api/env/params?fresh=1&_=' + Date.now()); + dbParams = await rDb.json(); + } catch(e) { console.warn('Failed to load db params', e); } + for (const d of jobData) { const gated = d.top5_gated || (d.result_summary && d.result_summary.top5_gated) || []; const stats = optunaCalcStats(gated); d._stats = stats; d._gatedList = gated; + d._dbData = dbParams[d.strategy || 'tail'] || {}; const lbl = (d.label || d.strategy || d.job_id || '').replace(/<[^>]+>/g,''); const sn = (d.study_short || '').replace(/<[^>]+>/g,''); @@ -11336,16 +11460,10 @@ async function compareSelectedJobs() { }}, { label:'์Šน๋ฅ  / PF', fn: g => `${pRound2(g.win_rate)}% / ${pRound2(g.pf)}` }, { label:'๊ฑฐ๋ž˜์ˆ˜ / trial', fn: g => `${g.total_trades??'โ€”'}๊ฑด / #${g.optuna_trial_number??'โ€”'}` }, - { label:'์ต์ ˆ tp(%)', fn: g => { - const v = g.tp_pct ?? null; - return v!=null?`${v}%`:'โ€”'; - }}, - { label:'์†์ ˆ sl(%)', fn: g => { - const v = g.sl_pct ?? null; - return v!=null?`${v}%`:'โ€”'; - }}, + { label:'์ต์ ˆ tp(%)', fn: (g, d) => formatWhipParam(g.tp_pct, '', '%', 1, 'tp_pct', null, false, d._dbData) || 'โ€”' }, + { label:'์†์ ˆ sl(%)', fn: (g, d) => formatWhipParam(g.sl_pct, '', '%', 1, 'sl_pct', null, false, d._dbData) || 'โ€”' }, { label:'ํ˜ธ๊ฐ€ ON', fn: (g) => g.ob_on!=null?(g.ob_on?'โœ…':'โŒ'):'โ€”' }, - { label:'ํŒŒ๋ผ๋ฏธํ„ฐ
(ํ˜ธ๊ฐ€ยท์ต์†์ ˆยทํœฉ์˜)', fn: (g, d) => optunaObWhipCell(g, d._stats) }, + { label:'ํŒŒ๋ผ๋ฏธํ„ฐ
(ํ˜ธ๊ฐ€ยท์ต์†์ ˆยทํœฉ์˜)', fn: (g, d) => optunaObWhipCell(g, d._stats, d._dbData) }, ]; for (let i = 0; i < maxTop; i++) { diff --git a/templates/backtest.html b/templates/backtest.html index 5c12b85..cbe7272 100644 --- a/templates/backtest.html +++ b/templates/backtest.html @@ -784,6 +784,14 @@ +
+
+ + +
+
์ง€ํ‘œ
์ง€ํ‘œ
์ดˆ๋ก ๋ฐ‘์ค„: DB์™€ ์œ ์‚ฌ