auto: 일일 백업 2026-06-12 02:00

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
hyowons
2026-06-12 02:00:03 +09:00
parent b20c21cbd2
commit defd5c0bf6
120 changed files with 627 additions and 208 deletions
+1 -1
View File
File diff suppressed because one or more lines are too long
+2 -2
View File
@@ -50,8 +50,8 @@
| `holiday-sync` | 매주 일요일 03:00 | `holiday_sync.py` | investing.com → `state/market_holidays.json`. 실패 시 기존 파일 보존 |
| `behive-web` | 상시 (`KeepAlive`) | `behive_web.py serve` | 3-탭 워치리스트 웹뷰. Tailscale `100.75.148.12:18790``https://stock.hyowons.net/`(Synology reverse proxy). 코드 변경 후 bootout/bootstrap 필요 |
| `trade-journal` | 평일 21:00 (스크립트가 휴장일 self-skip) | `trade_journal.py collect` | ka10170 당일매매일지 4계좌 → `state/trade_journal.jsonl` 누적. NXT 야간 마감 후 발화. 키움이 기간 거래내역 API 미제공이라 일자별 적재만이 유일. `briefing-fallback-2100`(21:00)과 같은 시각이지만 둘 다 read-only 충돌 없음. 재실행 시 (date,account) 단위 idempotent. **시드**: 2026-05-13 1회 `trade_journal.py seed` 로 적재 시작일 이전 보유분을 현재 평단가×(qty - tdy_buyq + tdy_sellq)로 단일 시드 행 압축(28건, seed=true 플래그, `*` 마커). 시드는 가중평균이라 과거 매수 단가와 정확히 일치 X. CLI: `collect`/`seed`/`show <code>`/`query --from --to --account --code` |
| `sim-scan` | 평일 09:0015:30 **매 5분** (`StartCalendarInterval` 79엔트리, 엔진이 장외/휴장 self-skip) ⚠️2026-06-09 15분→5분 단축 + `StartInterval` 900s→`StartCalendarInterval` 전환(StartInterval은 GUI세션 idle/디스플레이 sleep 시 timer coalescing으로 발화 보류돼 장중 안 돎. calendar는 git-autopush가 새벽 02:00 정상발화로 검증됨) | `python3 -m sim scan` (내부 `scan_all` — 메인+병렬변이 동시) | **자동매매 시뮬(페이퍼)** 1회 스캔. 가상자본 1억(2026-06-10 1천만→1억), 규칙 엔진(LLM 미경유). universe=비하이브 워치+관심+보유(**ETF/ETN은 2026-06-09부터 자동매수 제외** — 애널 방향성 부재로 전략 부정합, `universe.is_etf()` 프리픽스 판별, 보유분은 청산까지 추적). 방향=애널 약한게이트+가점, 타이밍=수급·기술(2026-06-09 시장강약 필터: 하드차단→소프트게이트+장중 실시간 상승비율 + **지수추세 이중확인**). **2026-06-09 4종 추가**: 리스크 기반 사이징(`signals.target_value` 수량=자산×`RISK_PER_TRADE_PCT`÷손절폭, 균등비중 캡)·RSI 필터(돌파 과열/눌림목 과매도 보류)·**시장 국면 6단계**(`market_regime_map``engine.REGIME`: 🔥강세·📈반등·🌤완만상승=매수허용 / ➖혼조·📉약세·❄️급락=보류. 상승비율+지수추세+당일등락 조합. market_ok·시장탭 공용. 강세/약세 2단계가 84% 반등을 약세로 오판해 세분화)·**약세장 매수모드**(`BEAR_ENTRY_MODE` 0현금화/1돌파만/2눌림허용, market_ok False일 때 signals 분기. backtest는 시장중립이라 무영향→병렬변이로 라이브 비교. 2026-06-09 메인(mode1)+약세현금화·약세눌림허용 변이로 비교군 구성)·시간손절(`MAX_HOLD_DAYS` 미진전 청산)·**추세 질 보강**(2026-06-09 trend_ok 게이트에 ①20일선 우상향 기울기 ②5>60 중기정배열 추가〔종목데이터, backtest 반영〕 + ③상대강도〔종목−지수 N일수익률, 라이브 전용 체크〕). 사이징·시간손절은 엔진·백테스트 공용 헬퍼. TUNABLE 27개. **2026-06-10 코드리뷰 보강**: ①수급DB 일일증분(trade-journal 21시 묶음 3번째 명령 `-m sim.backfill_flow --pages 1 --force` — stale시 백테스트 수급게이트 중립화됨) ②일별 성과이력 `state/sim/equity_history.json`(EOD 덮어쓰기, ph=파라미터해시) ③당일 재진입 쿨다운(`Portfolio.last_exit`, backtest 동일) ④장중 거래량 하루치 환산(`vol_time_frac` — 이전엔 오전 돌파 불가). ⑤백테스트 체결 현실화(당일종가 판단→다음날 시가 체결 pending큐 + `BT_SLIPPAGE` 0.2% — 낙관분 ~5%p 제거) ⑥3분할 꾸준함 순위(`worst_ret` 1순위 — 한 구간 운빨 배제) ⑧**기준전략(M) 폐지**(2026-06-10 — scan_all 메인 패스 execute=False 판단전용·계좌 동결, 비교/매매는 변이 36개만, 메인 제외 규칙 삭제, ⭐즐겨찾기 `favorites.json`+`/fav_toggle`, 관심종목 기본 시각=첫→1위) ⑦비교군 동기화는 **수동 전용**(2026-06-10 자동 동기화 끔 — sweep은 결과 파일만 갱신, 비교군 변경은 관리자님 명시 요청 시만 `python3 -m sim variants sync`. `sync_label_tops`=유형(~36종)별 1위 동기화, 동일params 계좌 유지. 백테스트 탭은 유형별 대표 읽기전용 요약, 수동 추가/제거·튜닝적용 버튼 제거). 잔여 한계: 검증 데이터가 여전히 ~1년 강세 위주(진짜 하락장 검증은 라이브 누적)·생존편향 universe(의도된 설계). 매수=돌파 즉시/눌림목 지정가, 매도=손절·2:1 후 트레일링·추세수급 이탈. 결과 `state/sim/`(portfolio.json·trades.jsonl·last_scan.json). 실주문 `orders/` 불가침. 일봉은 캐시 우선 읽기(ka10081 rate limit 회피). cwd=`agents/stock/workspace` |
| `sim-web` | 상시 (`KeepAlive`) | `python3 -m sim.sim_web serve` | 시뮬 대시보드 **별도 서버 포트 18792** (behive-web 18790과 분리). `sim.hyowons.net` → mac:18792 (Synology reverse proxy, **관리자님 수동 등록 대기**). Tailnet 한정 무인증. ⚠️ 18791은 node 점유라 18792. **5**: 계좌·관심종목·시장(지수/ADR/투자자)·튜닝(파라미터 저장 → `params.json`)·백테스트(스윕 순위표+적용). 읽기전용 원칙이나 `do_POST /save_params`만 쓰기. 시장 탭은 장중엔 네이버 m.stock 실시간(지수+상승하락·ADR·투자자 순매수, `_get_live_market` 60s 캐시), 장외엔 EOD jsonl 폴백 (2026-06-09: 이전엔 상승하락·투자자가 EOD 고정이라 장중 안 바뀌던 것 수정) |
| `sim-scan` | 평일 09:0015:30 **매 5분** (`StartCalendarInterval` 79엔트리, 엔진이 장외/휴장 self-skip) ⚠️2026-06-09 15분→5분 단축 + `StartInterval` 900s→`StartCalendarInterval` 전환(StartInterval은 GUI세션 idle/디스플레이 sleep 시 timer coalescing으로 발화 보류돼 장중 안 돎. calendar는 git-autopush가 새벽 02:00 정상발화로 검증됨) | `python3 -m sim scan` (내부 `scan_all` — 메인+병렬변이 동시) | **자동매매 시뮬(페이퍼)** 1회 스캔. 가상자본 1억(2026-06-10 1천만→1억), 규칙 엔진(LLM 미경유). universe=비하이브 워치+관심+보유(**ETF/ETN은 2026-06-09부터 자동매수 제외** — 애널 방향성 부재로 전략 부정합, `universe.is_etf()` 프리픽스 판별, 보유분은 청산까지 추적). 방향=애널 약한게이트+가점, 타이밍=수급·기술(2026-06-09 시장강약 필터: 하드차단→소프트게이트+장중 실시간 상승비율 + **지수추세 이중확인**). **2026-06-09 4종 추가**: 리스크 기반 사이징(`signals.target_value` 수량=자산×`RISK_PER_TRADE_PCT`÷손절폭, 균등비중 캡)·RSI 필터(돌파 과열/눌림목 과매도 보류)·**시장 국면 6단계**(`market_regime_map``engine.REGIME`: 🔥강세·📈반등·🌤완만상승=매수허용 / ➖혼조·📉약세·❄️급락=보류. 상승비율+지수추세+당일등락 조합. market_ok·시장탭 공용. 강세/약세 2단계가 84% 반등을 약세로 오판해 세분화)·**약세장 매수모드**(`BEAR_ENTRY_MODE` 0현금화/1돌파만/2눌림허용, market_ok False일 때 signals 분기. backtest는 시장중립이라 무영향→병렬변이로 라이브 비교. 2026-06-10 **유형36×모드3=108변이 풀매트릭스**로 확장, 첫 라이브 2026-06-11)·시간손절(`MAX_HOLD_DAYS` 미진전 청산)·**추세 질 보강**(2026-06-09 trend_ok 게이트에 ①20일선 우상향 기울기 ②5>60 중기정배열 추가〔종목데이터, backtest 반영〕 + ③상대강도〔종목−지수 N일수익률, 라이브 전용 체크〕). 사이징·시간손절은 엔진·백테스트 공용 헬퍼. TUNABLE 27개. **2026-06-10 코드리뷰 보강**: ①수급DB 일일증분(trade-journal 21시 묶음 3번째 명령 `-m sim.backfill_flow --pages 1 --force` — stale시 백테스트 수급게이트 중립화됨) ②일별 성과이력 `state/sim/equity_history.json`(EOD 덮어쓰기, ph=파라미터해시) ③당일 재진입 쿨다운(`Portfolio.last_exit`, backtest 동일) ④장중 거래량 하루치 환산(`vol_time_frac` — 이전엔 오전 돌파 불가). ⑤백테스트 체결 현실화(당일종가 판단→다음날 시가 체결 pending큐 + `BT_SLIPPAGE` 0.2% — 낙관분 ~5%p 제거) ⑥3분할 꾸준함 순위(`worst_ret` 1순위 — 한 구간 운빨 배제) ⑧**기준전략(M) 폐지**(2026-06-10 — scan_all 메인 패스 execute=False 판단전용·계좌 동결, 비교/매매는 변이 36개만, 메인 제외 규칙 삭제, 마킹 아이콘 6종 `favorites.json {아이콘:vid}`+`/fav_set`2026-06-11 ☆토글→아이콘 피커, 아이콘당 전략 1개〕, 관심종목 기본 시각=첫 마킹→1위) ⑦비교군 동기화는 **수동 전용**(2026-06-10 자동 동기화 끔 — sweep은 결과 파일만 갱신, 비교군 변경은 관리자님 명시 요청 시만 `python3 -m sim variants sync`. `sync_label_tops`=유형(~36종)별 1위 동기화, 동일params 계좌 유지. 백테스트 탭은 유형별 대표 읽기전용 요약, 수동 추가/제거·튜닝적용 버튼 제거). 잔여 한계: 검증 데이터가 여전히 ~1년 강세 위주(진짜 하락장 검증은 라이브 누적)·생존편향 universe(의도된 설계). 매수=돌파 즉시/눌림목 지정가, 매도=손절·2:1 후 트레일링·추세수급 이탈. 결과 `state/sim/`(portfolio.json·trades.jsonl·last_scan.json). 실주문 `orders/` 불가침. 일봉은 캐시 우선 읽기(ka10081 rate limit 회피). cwd=`agents/stock/workspace` |
| `sim-web` | 상시 (`KeepAlive`) | `python3 -m sim.sim_web serve` | 시뮬 대시보드 **별도 서버 포트 18792** (behive-web 18790과 분리). `sim.hyowons.net` → mac:18792 (Synology reverse proxy, **관리자님 수동 등록 대기**). Tailnet 한정 무인증. ⚠️ 18791은 node 점유라 18792. **3**(2026-06-10~11 개편, 내계좌·튜닝 탭 삭제): **전략**(기본=비교만, 서브탭 버튼 없음 — 백테스트 순위표는 [📊 모의결과보기] 토글)·**관심종목**(전 전략 합산 상태그룹 + 시각 드롭다운 + 👁토스트 맨 위 '▶ 시각' 판단 표시)·**시장**(지수/ADR/투자자). 비교 행 표기: 순위배지 `N위` → 약세장대처 칩(회피/안정/적극 — 2026-06-11 '돌파'→'안정' 개명, 칩 클릭=설명 토스트) → 고유번호 `#N` → 짧은 유형명(`상승장·빠른·공격·추세추종`) → 마킹 아이콘(6종 ⭐🔥💎🎯👀🚀, **아이콘당 전략 1개**, `favorites.json {아이콘:vid}`, `/fav_set`). 펼침 body: 유형(ⓘ=시장적합)→약세장대처(ⓘ)→성적→모의평가(`btN위/36` — 약세모드 3형제는 같은 bt등수 공유). **108변이 = 유형36 × 약세모드3**(2026-06-10 풀매트릭스, v37/38=bt1위의 회피/적극 쌍 순서). 새로고침 탭 보존(라디오↔URL 동기화 + `Cache-Control: no-store`, 2026-06-11). 읽기전용 원칙, 쓰기는 `do_POST` save_params/run_sweep/variants_*/watch_*/fav_set만. 시장 탭은 장중엔 네이버 m.stock 실시간(지수+상승하락·ADR·투자자 순매수, `_get_live_market` 60s 캐시), 장외엔 EOD jsonl 폴백 (2026-06-09: 이전엔 상승하락·투자자가 EOD 고정이라 장중 안 바뀌던 것 수정) |
| (트리거 없음) | on-demand | `python3 -m sim {sweep\|backtest}` | 튜닝 비교용 백테스트 스윕. signals.py 재사용·과거 일봉 되감기. 9파라미터(RR·STOP·SMA·PULLBACK·VOLUME + RSI과열/과매도·시간손절·리스크비율) 1152조합 학습/검증 분리 → `state/sim/backtest_results.json`. ⚡멀티프로세싱(2026-06-10 spawn, 워커=코어−2)+일봉/수급 프로세스 메모이즈 → 1152조합 44분→~5-7분. 데이터는 sqlite캐시 전용(키움API 0), 병목은 지표 재계산이라 캐싱 아닌 병렬화가 답. GRID 곱셈 폭발 주의. ⚠️ 종가체결·생존편향 → **상대순위**로만. 2026-06-09 스윕: 핵심 레버 `VOLUME_BREAKOUT=1.3`, 신규4종은 강세창선 미미(하락장 보험). 균형값 params.json 적용(RISK 0.01 유지). 수급은 `backfill_flow.py`(ka10059 다년치 → `flow_history.sqlite`, 2026-06-08 54종목 3만행 적재)로 반영됨(`flow_used:true`). 런타임 튜닝은 `params.json`이 config 기본값 오버라이드(엔진 매 스캔 새프로세스라 즉시 반영). **병렬 페이퍼**: `variants.json`+`state/sim/variants/<id>/` — 스윕 상위 튜닝을 각자 가상계좌로 실시간 동시 운영, 같은 라이브 시세에 다른 파라미터(애널 게이트까지 실반영), `variants_compare.json`→웹 비교 탭. `python3 -m sim variants seed N`. sim-scan이 매 스캔 메인+변이 함께 갱신 |
휴장일 self-skip·당일 평가손익 ground truth·3-탭 개편 배경은 일지(2026-05-04·05-06)와 `behive_web.py` 주석 참조. 사고 이력은 `memory/2026-05-07-behive-dup-mail.md` 등.
+300 -21
View File
@@ -8,6 +8,7 @@ sim state 파일(last_scan.json·portfolio.json·trades.jsonl)만 읽어 렌더.
"""
from __future__ import annotations
import hashlib
import html
import json
import subprocess
@@ -57,7 +58,7 @@ PTR_HTML = """
document.addEventListener('touchend',function(){
if(!pull)return;pull=false;
var d=dy*0.55;if(d>MAX)d=MAX;dy=0;
if(d>T){c.style.transform='translateY('+(T+15)+'px)';p.style.opacity='1';if(arrow)arrow.style.transform='';p.classList.add('spinning');location.reload();}
if(d>T){c.style.transform='translateY('+(T+15)+'px)';p.style.opacity='1';if(arrow)arrow.style.transform='';p.classList.add('spinning');location.href=(window._simURL?window._simURL():location.href);}
else{reset();}
});
})();</script>
@@ -74,6 +75,16 @@ REFRESH_JS = """
if(t==='acct'||t==='tune')t='lab'; /* 삭제된 탭 하위호환 */
if(t){var r=document.getElementById('tab-'+t); if(r)r.checked=true;}
if(s){var rs=document.getElementById('sub-'+s); if(rs)rs.checked=true;}
/* 탭 라디오 ↔ URL 동기화 — 어떤 새로고침(당겨서/브라우저/reload)이든 보던 탭으로 돌아오게 */
function simURL(){
var cur=TABS.find(function(x){var e=document.getElementById('tab-'+x);return e&&e.checked;});
var sub=SUBS.find(function(x){var e=document.getElementById('sub-'+x);return e&&e.checked;});
return '/?t='+(cur||'lab')+(cur==='lab'?'&s='+(sub||'cmp'):'')+((cur==='watch'&&vw)?'&view='+encodeURIComponent(vw):'');
}
window._simURL=simURL;
function syncUrl(){try{history.replaceState(null,'',simURL());}catch(e){}}
document.querySelectorAll('input[name="tab"],input[name="subtab"]').forEach(function(r2){r2.addEventListener('change',syncUrl);});
syncUrl();
function banner(msg,color){var b=document.createElement('div');b.className='saved-banner';
if(color)b.style.background=color;b.textContent=msg;document.body.appendChild(b);
setTimeout(function(){b.remove();},2800);}
@@ -281,7 +292,7 @@ _CHK_HELP = {
'상승여력': {'t': '상승여력 (목표가 대비)', 'd': '애널리스트 평균 목표주가가 지금 가격보다 몇 % 높은지예요. +20%면 전문가들이 20% 더 오를 여지를 본다는 의미예요. 이미 목표가 근처라 여력이 적으면 매력이 줄어요.'},
'목표가리비전': {'t': '목표가 리비전 (상향/하향)', 'd': '최근 애널리스트들이 목표주가를 올리는 중인지 내리는 중인지 봐요. "상향"이면 회사 전망이 좋아지는 방향이라 긍정 신호예요. "하향"이면 반대고요.'},
'어닝서프라이즈': {'t': '어닝 서프라이즈', 'd': '가장 최근 실적이 시장이 예상했던 것(컨센서스)보다 좋았는지(+) 나빴는지(−)예요. 예상보다 잘 나오면(서프라이즈 +) 주가에 긍정적으로 작용하는 경우가 많아요.'},
'시장강세': {'t': '시장 강세 (장 전체 분위기)', 'd': '그날 시장 전체에서 오른 종목의 비율이에요. 오른 종목이 기준(15%) 이상이면 "강세장"으로 봐요. 시장이 무너지는 날엔 좋은 종목도 같이 빠지기 쉬워서, 약세장에선 바닥잡기 매수는 잠깐 미루고 강한 돌파만 허용해요.'},
'시장강세': {'t': '시장 강세 (장 전체 분위기)', 'd': '그날 시장 전체 분위기(상승비율+지수추세+당일등락 조합)예요. 시장이 무너지는 날엔 좋은 종목도 같이 빠지기 쉬워서 참고하는데, 이 항목 하나로 매수가 막히는 건 아니에요 — 전략의 "약세장대처" 모드에 따라 갈려요. 회피=약세면 안 삼 · 안정(기본)=돌파만 삼 · 적극=눌림목도 삼. 그래서 약세(!)인데도 적극 전략은 정상적으로 매수할 수 있어요.'},
'과열': {'t': '과열 아님 (회전율)', 'd': '그날 거래 회전율(거래량을 상장주식 수로 나눈 값)이 평소 평균보다 지나치게(3배 이상) 높지 않은지 봐요. 너무 과열되면 단기 꼭대기일 위험이 커서, 그럴 땐 신규매수를 잠깐 보류해요.'},
'돌파': {'t': '돌파 (전고점)', 'd': '현재가가 최근 고점을 뚫고 올라갔는지예요. 전고점 돌파는 새로운 상승의 출발 신호로 봐요. 거래량·회전율 급증이 함께 나오면 "진짜 돌파"로 판단해 바로 매수합니다.'},
'거래량': {'t': '거래량 급증', 'd': '그날 거래량이 평소 평균보다 크게 많은지 봐요. 거래가 확 늘었다는 건 사람들의 관심이 몰렸다는 뜻이라, 돌파에 힘이 실렸는지 확인하는 신호예요.'},
@@ -317,9 +328,15 @@ def _chips(checks) -> str:
def chip(c):
k = _chk_key(c.get('label'))
info = f'<button type="button" class="chk-i" data-k="{k}" aria-label="설명">ⓘ</button>' if k else ''
ok = c.get('ok')
mark, color = _check_mark(ok), _check_color(ok)
# 시장 강세는 그 자체로 매수를 막는 필수조건이 아니라 약세장대처 모드로 분기되는
# 소프트 게이트 — 미충족이어도 빨간 ✗(위반 인상) 대신 노란 ! (참고)
if c.get('label') == '시장 강세' and ok is False:
mark, color = '!', '#eab308'
return (
f'<span class="chk" style="color:{_check_color(c.get("ok"))}">'
f'{_check_mark(c.get("ok"))} {_esc(c.get("label"))}'
f'<span class="chk" style="color:{color}">'
f'{mark} {_esc(c.get("label"))}'
f'<span class="cd">{_esc(c.get("detail"))}</span>{info}</span>'
)
@@ -726,14 +743,14 @@ def _market_fit_words(p: dict) -> str:
# 약세장 모드 단어 칩 — 비교군 행·드롭다운에서 한눈에 구분 (긴 접미사 대신).
_BEAR_WORD = {0: '회피', 1: '돌파', 2: '적극'}
_BEAR_NAME = {0: '회피 (현금화)', 1: '돌파 (기본)', 2: '적극 (눌림허용)'}
_BEAR_WORD = {0: '회피', 1: '안정', 2: '적극'}
_BEAR_NAME = {0: '회피 (현금화)', 1: '안정 (돌파만·기본)', 2: '적극 (눌림허용)'}
_BEAR_DESC = {
0: '이 전략은 시장이 약세 국면(혼조·약세·급락)이면 아무것도 안 사고 현금을 지켜요.',
1: '이 전략은 시장이 약세 국면이어도 강하게 치고 오르는 돌파 종목만 사요. 바닥잡기(눌림목 매수)는 안 해요.',
2: '이 전략은 시장이 약세 국면이어도 눌림목 저가매수까지 해요. 셋 중 가장 적극적이에요.',
}
_BEAR_LEGEND = '\n\n회피=약세장 매수 안 함 · 돌파=돌파만 매수(기본) · 적극=눌림목 저가매수도 함'
_BEAR_LEGEND = '\n\n회피=약세장 매수 안 함 · 안정=돌파만 매수(기본) · 적극=눌림목 저가매수도 함'
def _bear_mode(p) -> int:
@@ -943,17 +960,14 @@ def _compare_panel() -> str:
scanned = _load(config.LAST_SCAN_PATH, {}).get('scanned_at', '')[:16].replace('T', ' ')
head = (f'<div class="sub">실시간 누적 비교 · 마지막 스캔 {scanned or ""} '
f'· {len(rows_data)} (메인 포함)</div>'
'<div class="sub" style="color:#b45309">⚠ 같은 라이브 시세에 서로 다른 튜닝 동시 운영. '
'기간 길수록·거래 많을수록 신뢰 · 비교군 변경은 수동(코디에게 요청)</div>'
'<div class="sub">약세장대처: <span class="bic bic0">회피</span>매수 안 함 · '
'<span class="bic bic1">돌파</span>돌파만(기본) · '
'<span class="bic bic2">적극</span>눌림목도 매수 — 칩 클릭 시 설명</div>')
f'· 전략 {len(rows_data)}개</div>')
clear_btn = ('' if not defs else
'<form method="post" action="/variants_clear_all" style="display:inline;margin-left:8px" '
'onsubmit="return confirm(\'메인을 제외한 비교군 변이를 전부 삭제할까요?\')">'
f'<button type="submit" class="cmp-clear">🗑 전체삭제 {len(defs)}</button></form>')
title = f'<h2 class="cmp-title">병렬 페이퍼 비교{clear_btn}</h2>'
bt_btn = ('<label for="sub-bt" class="cmp-btlink" role="button" tabindex="0" '
'title="백테스트 순위표 보기">📊 모의결과보기</label>')
title = f'<h2 class="cmp-title">병렬 페이퍼 비교{clear_btn}{bt_btn}</h2>'
rows = ''
for i, v in enumerate(rows_data):
s = v['summary']
@@ -982,12 +996,17 @@ def _compare_panel() -> str:
f'onsubmit="return confirm(\'이 변이를 삭제할까요?\')">'
f'<input type="hidden" name="id" value="{_esc(v["id"])}">'
f'<button type="submit" class="btn-mini btn-danger">삭제</button></form>')
actions = f'<div class="cmp-row-actions">{reset_btn}{del_btn}</div>'
det_btn = (f'<a href="/strategy?id={_esc(v["id"])}" class="btn-mini" '
f'style="text-decoration:none">📈 자세히보기</a>')
actions = f'<div class="cmp-row-actions">{det_btn}{reset_btn}{del_btn}</div>'
vid = v['id']
_vk = _btkey(v.get('params') or {})
bt = bt_map.get(_vk)
gr = bt_grank.get(_vk)
bt_attr = gr if gr else 9999
# 평가순 정렬 키 = 고유번호 오름차순 (#1→#108) — 번호 자체가 평가순 부여라 그대로가 가장 직관적.
# bt 미매칭 변이만 뒤로. (등수×1000+번호 방식은 #1·#37·#38… 로 보여 뒤섞인 인상 — 2026-06-11 단순화)
_vnum = int(vid[1:]) if vid[1:].isdigit() else 999
bt_attr = _vnum if (bt and gr) else 900000 + _vnum
if bt and gr:
bw = f"{bt['worst']:+g}%" if bt['worst'] is not None else ''
bt_row = (f'<div class="kv nb"><span class="k">모의평가</span>'
@@ -1020,7 +1039,7 @@ def _compare_panel() -> str:
f'{bt_row}'
f'<details class="row"><summary><span class="nm">📦 보유종목 ({s.get("open_positions",0)})</span></summary>'
f'<div class="body">{_pos_table(v["pf"])}</div></details>'
f'<details class="row"><summary><span class="nm">📋 거래내역 ({s.get("closed_trades",0)}청산)</span></summary>'
f'<details class="row"><summary><span class="nm">📋 거래내역 ({_trade_count(v["tpath"])}건 · {s.get("closed_trades",0)}청산)</span></summary>'
f'<div class="body">{_trades_table(_read_trades(v["tpath"]))}</div></details>'
f'<details class="row"><summary><span class="nm">🎯 관심종목 ({len(w)})</span></summary>'
f'<div class="body">{watch_html}</div></details>'
@@ -1028,7 +1047,7 @@ def _compare_panel() -> str:
f'</div></details>'
)
sortbar = ('<div class="cmp-sortbar" id="cmp-sortbar">'
'<button type="button" data-s="rank">손익</button>'
'<button type="button" data-s="rank">손익</button>'
'<button type="button" data-s="bt">평가순</button>'
'<button type="button" data-s="held">보유순</button>'
'<button type="button" data-s="trades">거래순</button></div>')
@@ -1058,7 +1077,7 @@ def _compare_panel() -> str:
function post(vid, icon){
fetch('/fav_set',{method:'POST',headers:{'Content-Type':'application/x-www-form-urlencoded'},
body:'id='+encodeURIComponent(vid)+'&icon='+encodeURIComponent(icon)})
.then(function(){location.reload();});
.then(function(){location.href=(window._simURL?window._simURL():location.href);});
}
document.addEventListener('click',function(e){
var b=e.target.closest('.fav-b'); if(!b) return;
@@ -1100,6 +1119,246 @@ def _compare_panel() -> str:
return title + head + sortbar + f'<div id="cmp-rows">{rows}</div>' + sort_js + fav_js
def _ret_chart_svg(series, idx_series) -> str:
"""일별 누적수익률 라인차트 — 전략(실선) vs KOSPI(회색 점선, 같은 구간 등락률).
series=[(yyyymmdd, ret%)], idx_series=[ret%|None] (series와 같은 길이)."""
if not series:
return '<div class="empty">아직 수익률 이력이 없어요 — 매 거래일 하나씩 쌓입니다</div>'
w, h = 720, 230
pl, pr, pt, pb = 50, 14, 16, 28
rets = [r for _, r in series]
vals = rets + [r for r in idx_series if r is not None] + [0]
lo, hi = min(vals), max(vals)
span = (hi - lo) or 1.0
lo -= span * 0.15; hi += span * 0.15; span = hi - lo
n = len(series)
def X(i): return pl + (w - pl - pr) * (i / max(n - 1, 1))
def Y(v): return pt + (h - pt - pb) * (1 - (v - lo) / span)
color = '#22c55e' if rets[-1] >= 0 else '#ef4444'
parts = [f'<svg viewBox="0 0 {w} {h}" style="width:100%;height:auto" xmlns="http://www.w3.org/2000/svg">']
# 0% 기준선 + y축 라벨
parts.append(f'<line x1="{pl}" y1="{Y(0):.1f}" x2="{w-pr}" y2="{Y(0):.1f}" stroke="#334155" stroke-dasharray="4 4"/>')
for v in {round(hi - span * 0.15, 1), 0.0, round(lo + span * 0.15, 1)}:
parts.append(f'<text x="{pl-6}" y="{Y(v)+4:.1f}" text-anchor="end" font-size="11" fill="#64748b">{v:+g}%</text>')
# KOSPI 점선
ipts = [(i, r) for i, r in enumerate(idx_series) if r is not None]
if len(ipts) >= 2:
d = ' '.join(f'{X(i):.1f},{Y(r):.1f}' for i, r in ipts)
parts.append(f'<polyline points="{d}" fill="none" stroke="#64748b" stroke-width="1.5" stroke-dasharray="5 4"/>')
# 전략 실선 + 점
if n >= 2:
d = ' '.join(f'{X(i):.1f},{Y(r):.1f}' for i, r in enumerate(rets))
parts.append(f'<polyline points="{d}" fill="none" stroke="{color}" stroke-width="2.5"/>')
for i, r in enumerate(rets):
parts.append(f'<circle cx="{X(i):.1f}" cy="{Y(r):.1f}" r="3" fill="{color}"/>')
parts.append(f'<text x="{X(n-1):.1f}" y="{Y(rets[-1])-8:.1f}" text-anchor="end" font-size="12" '
f'font-weight="700" fill="{color}">{rets[-1]:+g}%</text>')
# x축 날짜 (처음·끝, 5개 이상이면 중간도)
ticks = sorted({0, n - 1} | ({n // 2} if n >= 5 else set()))
for i in ticks:
dt = series[i][0]
parts.append(f'<text x="{X(i):.1f}" y="{h-8}" text-anchor="middle" font-size="11" '
f'fill="#64748b">{dt[4:6]}/{dt[6:8]}</text>')
parts.append('</svg>')
legend = (f'<div class="sub" style="margin-top:2px"><span style="color:{color}">━ 이 전략</span>'
+ (' · <span style="color:#64748b">┅ KOSPI(같은 구간)</span>' if len(ipts) >= 2 else '') + '</div>')
return ''.join(parts) + legend
def _strategy_page(vid: str) -> str:
"""전략 1개 자세히보기 — 수익률 차트 + 분석. /strategy?id=vN"""
from . import variants as vmod, benchmark
defs = vmod.load_variants()
v = next((x for x in defs if x['id'] == vid), None)
back = '<a class="cmp-btlink" style="text-decoration:none" href="/?t=lab&s=cmp">← 비교로</a>'
style = """<style>
*{box-sizing:border-box}body{margin:0;background:#0b0f14;color:#e5e7eb;font-family:-apple-system,'Apple SD Gothic Neo',sans-serif;font-size:14px}
#page{max-width:760px;margin:0 auto;padding:14px 14px 40px}
h1{font-size:17px;margin:10px 0 2px}h2{font-size:14px;margin:22px 0 8px;color:#cbd5e1}
.sub{color:#6b7280;font-size:12px;margin:2px 0}
.card{background:#111824;border:1px solid #1f2937;border-radius:10px;padding:12px;margin:10px 0}
.kv{display:flex;justify-content:space-between;gap:12px;padding:5px 0;font-size:13px;border-bottom:1px solid #10161e;font-variant-numeric:tabular-nums}
.kv:last-child{border-bottom:none}.kv .k{color:#6b7280;font-size:12px;white-space:nowrap}
.muted{color:#6b7280}.empty{color:#475569;padding:14px 0;text-align:center;font-size:13px}
.vid{background:#1e293b;color:#7dd3fc;border-radius:5px;padding:1px 6px;font-size:11px;font-weight:700}
.bic{border-radius:5px;padding:1px 5px;font-size:10px;font-weight:700;margin-left:4px}
.bic0{background:#334155;color:#cbd5e1}.bic1{background:#1e3a5f;color:#7dd3fc}.bic2{background:#4a2e12;color:#fbbf24}
.cmp-btlink{background:#0f2a3f;color:#7dd3fc;border:1px solid #1e3a5f;border-radius:6px;padding:3px 8px;font-size:11px;font-weight:600;display:inline-block}
.note{white-space:pre-wrap;line-height:1.65;font-size:13px;color:#cbd5e1}
ul.an{margin:6px 0;padding-left:18px;line-height:1.7;font-size:13px}
details.row{border-top:1px solid #1f2937;padding:6px 0}summary{cursor:pointer;font-size:13px}
details.row summary{display:flex;gap:6px;align-items:center}
details.row summary .nm{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
details.row summary .rt{flex:0 0 auto;font-size:12px}
details.row .body{padding:6px 2px 2px}
table{width:100%;border-collapse:collapse;font-size:12px}td,th{padding:4px 6px;border-bottom:1px solid #10161e;text-align:right}
td:first-child,th:first-child{text-align:left}
/* 판단근거 칩 (거래내역) — 본 대시보드와 동일 줄바꿈 레이아웃 */
.chks{display:flex;flex-wrap:wrap;gap:5px;margin:4px 0 2px}
.chk{background:#0f151c;border:1px solid #1f2937;border-radius:6px;padding:2px 7px;font-size:11px;display:inline-block}
.chk .cd{color:#6b7280;margin-left:5px}
.chk-i{background:none;border:none;color:#60a5fa;font-size:11px;cursor:pointer;padding:0 0 0 4px;line-height:1;vertical-align:baseline}
.chk-paths{flex-basis:100%;margin-top:5px;border-top:1px dashed #283347;padding-top:6px}
.path-cap{font-size:10px;color:#64748b;margin-bottom:5px;cursor:pointer}
.path-line{display:flex;gap:8px;align-items:flex-start;padding:6px 0}
.path-line + .path-line{border-top:1px dashed #1f2937}
.path-line .path-h{flex:0 0 72px;font-size:11px;font-weight:700;padding-top:3px}
.path-line .path-items{display:flex;flex-wrap:wrap;gap:5px;min-width:0}
#chk-toast{position:fixed;inset:0;z-index:100;background:rgba(0,0,0,.55);display:flex;align-items:flex-end;justify-content:center}
#chk-toast .ct-card{background:#141b24;border:1px solid #2952cc;border-radius:14px 14px 0 0;padding:16px 18px 22px;max-width:520px;width:100%;box-shadow:0 -4px 24px rgba(0,0,0,.5)}
#chk-toast .ct-t{font-size:15px;font-weight:700;color:#fff;margin-bottom:8px}
#chk-toast .ct-d{font-size:13px;line-height:1.6;color:#cbd5e1;white-space:pre-line;max-height:55vh;overflow-y:auto}
#chk-toast .ct-x{margin-top:14px;width:100%;background:#1e3a8a;color:#fff;border:1px solid #2952cc;border-radius:9px;padding:10px;font-size:13px;font-weight:600;cursor:pointer}
</style>"""
if not v:
return (f'<!DOCTYPE html><html lang="ko"><head><meta charset="utf-8">'
f'<meta name="viewport" content="width=device-width,initial-scale=1">{style}</head>'
f'<body><div id="page">{back}<div class="empty">전략 {_esc(vid)}을 찾을 수 없어요 (삭제됐을 수 있음)</div></div></body></html>')
params = v.get('params') or {}
bm = _bear_mode(params)
pp, tp = vmod.variant_paths(vid)
pf = Portfolio.load(pp, tp)
s = pf.summary()
ret = s.get('total_return_pct', 0) or 0
today = datetime.now(config.KST).strftime('%Y%m%d')
bench = benchmark.compare(ret, benchmark.norm_date(pf.created_at), today)
# 순위·마킹·관심종목 (비교 스냅샷)
cv = [c for c in (_load(vmod.COMPARE_PATH, {}) or {}).get('variants', []) if c.get('id') != 'main']
ranked = sorted(cv, key=lambda c: c['summary'].get('total_return_pct', 0) or 0, reverse=True)
rank = {c['id']: n + 1 for n, c in enumerate(ranked)}.get(vid)
watching = next((c.get('watching', []) or [] for c in cv if c.get('id') == vid), [])
icon = {vv: ic for ic, vv in _load_favs().items()}.get(vid, '')
# 모의평가(백테스트 등록 근거) — 비교탭과 동일 매칭(swept만)
btres = _load(config.STATE_DIR / 'backtest_results.json', None) or {}
swept = btres.get('swept_params') or []
key = _pkey({k: params[k] for k in swept if k in params} if swept else params)
bt, _rk, _seen = None, 0, set()
for r in btres.get('results', []):
kk = _pkey(r['params'])
if kk in _seen:
continue
_seen.add(kk); _rk += 1
if kk == key:
bt = {**r, 'rank': _rk}
break
# 수익률 이력 (id+파라미터해시 매칭 — id 재사용 오염 방지) + KOSPI 같은 구간
ph = hashlib.md5(json.dumps(params, sort_keys=True).encode()).hexdigest()[:8]
eh = _load(config.STATE_DIR / 'equity_history.json', {}) or {}
series = [(d, e.get('ret', 0)) for d in sorted(eh) for e in eh[d]
if e.get('id') == vid and e.get('ph') == ph]
kospi = (_load(config.STATE_DIR / 'index_history.json', {}) or {}).get('KOSPI', {})
idx_series = []
base = kospi.get(series[0][0]) if series else None
for d, _ in series:
c = kospi.get(d)
idx_series.append(round((c / base - 1) * 100, 2) if (c and base) else None)
# 종합 코멘트 (결정론 — LLM 미경유)
notes = []
rk_s = f'#{rank}위/{len(ranked)}' if rank else '순위 산정 전'
notes.append(f'운영 {len(series) or 1}일째 · 현재 {rk_s} · 누적 <b>{ret:+.2f}%</b>')
ak = (bench.get('KOSPI') or {}).get('alpha')
if ak is not None:
notes.append(f'같은 기간 KOSPI 대비 <b>{ak:+.2f}%p</b> — '
+ ('지수를 이기고 있어요' if ak > 0 else '아직 지수에 못 미쳐요' if ak < 0 else '지수와 동률'))
nt, npos = s.get('closed_trades', 0) or 0, s.get('open_positions', 0) or 0
if not nt and not npos:
notes.append('아직 거래가 없어요 — 진입 조건 충족을 기다리는 중')
else:
if npos:
notes.append(f'현재 {npos}종목 보유 중 (주식 {s.get("held_value", 0):,}원)')
if nt:
notes.append(f'청산 {nt}건 · 승률 {s.get("win_rate_pct")}%'
+ (' — 표본이 적어 아직 참고만' if nt < 5 else ''))
if bt:
tr_, te_ = bt['train'].get('total_return_pct', 0), bt['test'].get('total_return_pct', 0)
if (tr_ - te_) > 40:
notes.append('⚠ 백테스트 학습-검증 격차가 커요 — 과최적 가능성, 라이브 성적을 더 지켜봐야')
notes_html = '<ul class="an">' + ''.join(f'<li>{x}</li>' for x in notes) + '</ul>'
# 모의평가 카드
if bt:
wins = ' / '.join((f"{w['ret']:+g}%" if w.get('ret') is not None else '') for w in bt.get('windows', []))
worst = bt.get('worst_ret')
bt_html = (
_kvline('전체 순위', f'#{bt["rank"]}위 (고유 조합 기준)')
+ _kvline('검증 수익 / 학습 수익', f'{bt["test"].get("total_return_pct"):+g}% / {bt["train"].get("total_return_pct"):+g}%')
+ _kvline('3분할 구간 수익', wins or '')
+ _kvline('최악 구간', f'{worst:+g}%' if worst is not None else '')
+ _kvline('검증 MDD / 승률 / PF',
f'{bt["test"].get("mdd_pct")}% · {bt["test"].get("win_rate_pct")}% · {bt["test"].get("profit_factor")}')
+ '<div class="sub">과거 데이터 모의평가 — 다음날 시가 체결·슬리피지 반영, 절대수익이 아닌 상대 비교용</div>')
else:
bt_html = '<div class="empty">백테스트 기록 없음 (등록 이후 스윕 미실행)</div>'
# 파라미터 표
prow = ''
for k in sorted(params):
hlp = _TUNE_HELP.get(k, {})
prow += (f'<tr><td>{_esc(hlp.get("t", k))}<br><span class="muted">{_esc(k)}</span></td>'
f'<td>{params[k]:g}</td></tr>')
mf_t, mf_b = _market_fit(params)
watch_html = ''.join(
f'<div class="kv"><span class="k">{_esc(it.get("name", ""))}</span>'
f'<span class="muted">{_esc(it.get("reason", ""))[:34]}</span></div>'
for it in watching) or '<div class="empty">노리는 종목 없음</div>'
rc = '#22c55e' if ret >= 0 else '#ef4444'
alpha_html = _alpha_inline(bench)
return f"""<!DOCTYPE html><html lang="ko"><head><meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>{_esc(vid)} 전략 상세</title>{style}</head><body><div id="page">
{back}
<h1><span class="vid">{rank or ""}위</span> <span class="muted">{_vid_disp(vid)}</span> {_esc(_market_fit_words(params))}
<span class="bic bic{bm}">{_BEAR_WORD[bm]}</span> {icon}</h1>
<div class="sub">{_esc(_market_fit_summary(params))} · 약세장대처: {_BEAR_NAME[bm]}</div>
<div class="card">{notes_html}</div>
<h2>📈 수익률 추이</h2>
<div class="card">{_ret_chart_svg(series, idx_series)}</div>
<h2>현재 성적</h2>
<div class="card">
{_kvline('평가자산', f'{s.get("equity", 0):,}')}
{_kvline('수익률', f'<b style="color:{rc}">{ret:+.2f}%</b>')}
{_kvline('예수금 / 주식', f'{s.get("cash", 0):,} / {s.get("held_value", 0):,}')}
{_kvline('실현손익', f'{s.get("realized_pnl", 0):,}')}
{_kvline('거래 / 승률', f'{s.get("closed_trades", 0)}건 · {s.get("win_rate_pct")}%')}
{_kvline('MDD / 보유', f'{s.get("max_drawdown_pct", 0)}% · {s.get("open_positions", 0)}종목')}
{_kvline('지수대비(알파)', alpha_html)}
</div>
<h2>모의평가 (등록 근거)</h2>
<div class="card">{bt_html}</div>
<h2>전략 성격 — 어떤 시장에 강한가</h2>
<div class="card"><div class="note">{_esc(mf_b)}</div></div>
<h2>약세장대처 — {_BEAR_NAME[bm]}</h2>
<div class="card"><div class="note">{_esc(_BEAR_DESC[bm])}</div></div>
<h2>파라미터 ({len(params)}개)</h2>
<div class="card"><table><tr><th>항목</th><th>값</th></tr>{prow}</table></div>
<h2>보유·관심·거래</h2>
<div class="card">
<details class="row"><summary>📦 보유종목 ({s.get("open_positions", 0)})</summary>{_pos_table(pf)}</details>
<details class="row"><summary>🎯 관심종목 ({len(watching)})</summary>{watch_html}</details>
<details class="row"><summary>📋 거래내역 ({_trade_count(tp)}건 · {s.get("closed_trades", 0)}청산)</summary>{_trades_table(_read_trades(tp))}</details>
</div>
<div class="sub" style="margin-top:18px">수익률 이력은 매 거래일 EOD 기준 1점씩 누적 · 분석은 규칙 기반(LLM 미경유)</div>
</div>
{_CHK_HELP_JS}
</body></html>"""
def _engine_status(snap, asset_line) -> tuple[str, str]:
"""스캔 엔진 헬스 → (점 클래스 ok/idle/bad, 토스트 상세). 장중 최근스캔=초록, 장중 멈춤=빨강, 장외=대기."""
now = datetime.now(config.KST)
@@ -1157,6 +1416,14 @@ def _pos_table(pf) -> str:
return rows or '<div class="empty">보유 종목 없음</div>'
def _trade_count(path) -> int:
"""거래로그(jsonl) 총 건수 (매수+매도)."""
try:
return sum(1 for ln in path.read_text().splitlines() if ln.strip())
except Exception:
return 0
def _read_trades(path, limit=30) -> list:
"""거래로그(jsonl) 최근 limit건, 최신순."""
out = []
@@ -1468,6 +1735,7 @@ h3.grp{{font-size:13px;margin:16px 0 8px;color:#cbd5e1}}
.bt-type .bt-type-d{{display:block;font-size:11px;font-weight:400;color:#9ca3af;margin-top:2px}}
.cmp-title{{display:flex;align-items:center}}
.cmp-clear{{background:#3a1518;color:#fca5a5;border:1px solid #7f1d1d;border-radius:6px;padding:3px 8px;font-size:11px;font-weight:600;cursor:pointer}}
.cmp-btlink{{background:#0f2a3f;color:#7dd3fc;border:1px solid #1e3a5f;border-radius:6px;padding:3px 8px;font-size:11px;font-weight:600;cursor:pointer;margin-left:8px;display:inline-block}}
#judge-view{{background:#141b24;border:1px solid #2a3142;color:#e5e7eb;border-radius:6px;padding:3px 6px;font-size:10px;max-width:88%}}
.fav-b{{background:none;border:none;font-size:13px;cursor:pointer;padding:0 2px;line-height:1;flex:0 0 auto}}
.fav-none{{opacity:.35;filter:grayscale(1)}}
@@ -1594,9 +1862,8 @@ input[name="tab"],input[name="subtab"]{{display:none}}
<h2>시장 동향</h2>{market_html}
</section>
<section class="panel" id="p-lab">
<nav class="subtabs"><label for="sub-cmp">비교</label><label for="sub-bt">백테스트</label></nav>
<div class="subpanel" id="ps-cmp">{cmp_html}</div>
<div class="subpanel" id="ps-bt"><h2>백테스트 순위표</h2>{bt_html}</div>
<div class="subpanel" id="ps-bt"><h2 class="cmp-title">백테스트 순위표 <label for="sub-cmp" class="cmp-btlink" role="button" tabindex="0">← 비교로</label></h2>{bt_html}</div>
</section>
<div class=sub style="margin-top:20px">60초 자동 새로고침 · 당겨서 새로고침 · sim/ 가상 엔진 (실주문 아님)</div>
</div>
@@ -1625,6 +1892,16 @@ class Handler(BaseHTTPRequestHandler):
self.end_headers()
self.wfile.write(body)
return
if path == '/strategy':
vid = (urllib.parse.parse_qs(parsed.query).get('id') or [''])[0]
body = _strategy_page(vid).encode('utf-8')
self.send_response(200)
self.send_header('Content-Type', 'text/html; charset=utf-8')
self.send_header('Cache-Control', 'no-store')
self.send_header('Content-Length', str(len(body)))
self.end_headers()
self.wfile.write(body)
return
if path not in ('/', '/index.html'):
self.send_response(404)
self.end_headers()
@@ -1633,6 +1910,8 @@ class Handler(BaseHTTPRequestHandler):
body = render_html(view=_view).encode('utf-8')
self.send_response(200)
self.send_header('Content-Type', 'text/html; charset=utf-8')
# 캐시 금지 — Safari 휴리스틱 캐싱이 옛 HTML/JS를 재사용해 탭 복원 로직이 구버전으로 돌던 문제 방지
self.send_header('Cache-Control', 'no-store')
self.send_header('Content-Length', str(len(body)))
self.end_headers()
self.wfile.write(body)
@@ -26,3 +26,5 @@
{"date": "2026-06-09", "market": "KOSPI", "market_label": "코스피", "rise": 774, "upper": 1, "fall": 133, "lower": 1, "steady": 15, "adr": 578.36, "personal": -6167, "foreign": -20064, "institutional": 25048, "captured_at": "2026-06-09T21:00:02.663326+09:00"}
{"date": "2026-06-10", "market": "KOSDAQ", "market_label": "코스닥", "rise": 499, "upper": 6, "fall": 1176, "lower": 1, "steady": 61, "adr": 42.91, "personal": 1167, "foreign": 1420, "institutional": -1125, "captured_at": "2026-06-10T21:00:04.276904+09:00"}
{"date": "2026-06-10", "market": "KOSPI", "market_label": "코스피", "rise": 343, "upper": 2, "fall": 550, "lower": 0, "steady": 28, "adr": 62.73, "personal": 48643, "foreign": -27754, "institutional": -22665, "captured_at": "2026-06-10T21:00:04.276904+09:00"}
{"date": "2026-06-11", "market": "KOSDAQ", "market_label": "코스닥", "rise": 1219, "upper": 10, "fall": 457, "lower": 0, "steady": 59, "adr": 268.93, "personal": -3634, "foreign": -3601, "institutional": 7149, "captured_at": "2026-06-11T21:00:01.845336+09:00"}
{"date": "2026-06-11", "market": "KOSPI", "market_label": "코스피", "rise": 576, "upper": 3, "fall": 320, "lower": 0, "steady": 25, "adr": 180.94, "personal": 20803, "foreign": -14640, "institutional": -7561, "captured_at": "2026-06-11T21:00:01.845336+09:00"}
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -9,5 +9,5 @@
"max_drawdown": 0.0,
"last_exit": {},
"created_at": "2026-06-11T09:00:01.943184+09:00",
"updated_at": "2026-06-11T11:20:01.454247+09:00"
"updated_at": "2026-06-11T15:25:06.464885+09:00"
}
@@ -9,5 +9,5 @@
"max_drawdown": 0.0,
"last_exit": {},
"created_at": "2026-06-11T09:00:01.943289+09:00",
"updated_at": "2026-06-11T11:20:01.482275+09:00"
"updated_at": "2026-06-11T15:25:06.550097+09:00"
}
@@ -9,5 +9,5 @@
"max_drawdown": 0.0,
"last_exit": {},
"created_at": "2026-06-11T09:00:01.944222+09:00",
"updated_at": "2026-06-11T11:20:02.415842+09:00"
"updated_at": "2026-06-11T15:25:07.503889+09:00"
}
@@ -9,5 +9,5 @@
"max_drawdown": 0.0,
"last_exit": {},
"created_at": "2026-06-11T09:00:01.944232+09:00",
"updated_at": "2026-06-11T11:20:02.416974+09:00"
"updated_at": "2026-06-11T15:25:07.505039+09:00"
}
@@ -9,5 +9,5 @@
"max_drawdown": 0.0,
"last_exit": {},
"created_at": "2026-06-11T09:00:01.944241+09:00",
"updated_at": "2026-06-11T11:20:02.418131+09:00"
"updated_at": "2026-06-11T15:25:07.506218+09:00"
}
@@ -9,5 +9,5 @@
"max_drawdown": 0.0,
"last_exit": {},
"created_at": "2026-06-11T09:00:01.944251+09:00",
"updated_at": "2026-06-11T11:20:02.419264+09:00"
"updated_at": "2026-06-11T15:25:07.507372+09:00"
}
@@ -9,5 +9,5 @@
"max_drawdown": 0.0,
"last_exit": {},
"created_at": "2026-06-11T09:00:01.944261+09:00",
"updated_at": "2026-06-11T11:20:02.420394+09:00"
"updated_at": "2026-06-11T15:25:07.508515+09:00"
}
@@ -9,5 +9,5 @@
"max_drawdown": 0.0,
"last_exit": {},
"created_at": "2026-06-11T09:00:01.944270+09:00",
"updated_at": "2026-06-11T11:20:02.421522+09:00"
"updated_at": "2026-06-11T15:25:07.509676+09:00"
}
@@ -18,7 +18,7 @@
"scaled_out": false,
"entry_path": "pullback",
"entry_reason": "눌림목 지정가 232,280 도달",
"cur_price": 221000,
"cur_price": 222000,
"tranches": 1,
"tranche_value": 3741721.8543046354,
"last_add_price": 226000
@@ -28,8 +28,8 @@
"closed_trades": 0,
"wins": 0,
"peak_equity": 100000000,
"max_drawdown": 0.0008054240000000596,
"max_drawdown": 0.0010454240000000595,
"last_exit": {},
"created_at": "2026-06-11T09:00:01.944280+09:00",
"updated_at": "2026-06-11T11:20:02.422680+09:00"
"updated_at": "2026-06-11T15:25:07.510844+09:00"
}
@@ -9,5 +9,5 @@
"max_drawdown": 0.0,
"last_exit": {},
"created_at": "2026-06-11T09:00:01.944290+09:00",
"updated_at": "2026-06-11T11:20:02.423836+09:00"
"updated_at": "2026-06-11T15:25:07.512007+09:00"
}
@@ -9,5 +9,5 @@
"max_drawdown": 0.0,
"last_exit": {},
"created_at": "2026-06-11T09:00:01.944300+09:00",
"updated_at": "2026-06-11T11:20:02.424970+09:00"
"updated_at": "2026-06-11T15:25:07.513155+09:00"
}
@@ -9,5 +9,5 @@
"max_drawdown": 0.0,
"last_exit": {},
"created_at": "2026-06-11T09:00:01.943299+09:00",
"updated_at": "2026-06-11T11:20:01.484250+09:00"
"updated_at": "2026-06-11T15:25:06.552450+09:00"
}
@@ -9,5 +9,5 @@
"max_drawdown": 0.0,
"last_exit": {},
"created_at": "2026-06-11T09:00:01.943310+09:00",
"updated_at": "2026-06-11T11:20:01.486076+09:00"
"updated_at": "2026-06-11T15:25:06.554689+09:00"
}
@@ -9,5 +9,5 @@
"max_drawdown": 0.0,
"last_exit": {},
"created_at": "2026-06-11T09:00:01.943320+09:00",
"updated_at": "2026-06-11T11:20:02.273225+09:00"
"updated_at": "2026-06-11T15:25:07.358839+09:00"
}
@@ -9,5 +9,5 @@
"max_drawdown": 0.0,
"last_exit": {},
"created_at": "2026-06-11T09:00:01.943331+09:00",
"updated_at": "2026-06-11T11:20:02.280336+09:00"
"updated_at": "2026-06-11T15:25:07.366171+09:00"
}
@@ -9,5 +9,5 @@
"max_drawdown": 0.0,
"last_exit": {},
"created_at": "2026-06-11T09:00:01.943342+09:00",
"updated_at": "2026-06-11T11:20:02.285017+09:00"
"updated_at": "2026-06-11T15:25:07.370543+09:00"
}
@@ -9,5 +9,5 @@
"max_drawdown": 0.0,
"last_exit": {},
"created_at": "2026-06-11T09:00:01.943352+09:00",
"updated_at": "2026-06-11T11:20:02.288698+09:00"
"updated_at": "2026-06-11T15:25:07.374468+09:00"
}
@@ -9,5 +9,5 @@
"max_drawdown": 0.0,
"last_exit": {},
"created_at": "2026-06-11T09:00:01.943361+09:00",
"updated_at": "2026-06-11T11:20:02.291899+09:00"
"updated_at": "2026-06-11T15:25:07.377881+09:00"
}
@@ -9,5 +9,5 @@
"max_drawdown": 0.0,
"last_exit": {},
"created_at": "2026-06-11T09:00:01.943371+09:00",
"updated_at": "2026-06-11T11:20:02.294962+09:00"
"updated_at": "2026-06-11T15:25:07.381990+09:00"
}
@@ -9,5 +9,5 @@
"max_drawdown": 0.0,
"last_exit": {},
"created_at": "2026-06-11T09:00:01.943381+09:00",
"updated_at": "2026-06-11T11:20:02.298815+09:00"
"updated_at": "2026-06-11T15:25:07.385291+09:00"
}
@@ -9,5 +9,5 @@
"max_drawdown": 0.0,
"last_exit": {},
"created_at": "2026-06-11T09:00:01.943203+09:00",
"updated_at": "2026-06-11T11:20:01.463659+09:00"
"updated_at": "2026-06-11T15:25:06.526338+09:00"
}
@@ -9,5 +9,5 @@
"max_drawdown": 0.0,
"last_exit": {},
"created_at": "2026-06-11T09:00:01.943391+09:00",
"updated_at": "2026-06-11T11:20:02.301973+09:00"
"updated_at": "2026-06-11T15:25:07.388354+09:00"
}
@@ -9,5 +9,5 @@
"max_drawdown": 0.0,
"last_exit": {},
"created_at": "2026-06-11T09:00:01.943400+09:00",
"updated_at": "2026-06-11T11:20:02.304954+09:00"
"updated_at": "2026-06-11T15:25:07.391455+09:00"
}
@@ -1,13 +1,35 @@
{
"cash": 100000000,
"cash": 95790868.725,
"initial": 100000000,
"positions": {},
"positions": {
"035420": {
"code": "035420",
"name": "NAVER",
"sources": [
"interest"
],
"qty": 19,
"entry_price": 221500,
"entry_at": "2026-06-11T12:45:02.417933+09:00",
"stop": 195800,
"target": 272900,
"peak": 224000,
"trailing_on": false,
"scaled_out": false,
"entry_path": "pullback",
"entry_reason": "눌림목 지정가 232,280 도달",
"cur_price": 222000,
"tranches": 1,
"tranche_value": 4309338.521400778,
"last_add_price": 221500
}
},
"realized_pnl": 0.0,
"closed_trades": 0,
"wins": 0,
"peak_equity": 100000000,
"max_drawdown": 0.0,
"peak_equity": 100046868.725,
"max_drawdown": 0.0004747774778495448,
"last_exit": {},
"created_at": "2026-06-11T09:00:01.943410+09:00",
"updated_at": "2026-06-11T11:20:02.307938+09:00"
"updated_at": "2026-06-11T15:25:07.394259+09:00"
}
@@ -0,0 +1 @@
{"ts": "2026-06-11T12:45:02.417938+09:00", "side": "BUY", "code": "035420", "name": "NAVER", "price": 221500, "qty": 19, "cost": 4209131, "path": "pullback", "reason": "눌림목 지정가 232,280 도달", "stop": 195800, "target": 272900, "signals": [{"label": "추세(20일선 위)", "ok": true, "detail": "221,000 vs 218,048"}, {"label": "정배열(5>20)", "ok": true, "detail": "256,000 / 218,048"}, {"label": "추세 기울기(20일선↑)", "ok": true, "detail": "우상향"}, {"label": "중기 정배열(5>60)", "ok": true, "detail": "256,000 / 215,415"}, {"label": "상대강도(시장대비)", "ok": true, "detail": "+3.8%p"}, {"label": "수급(5일 외/기)", "ok": true, "detail": "외 -132 · 기 +1,200 (천주)"}, {"label": "투자의견", "ok": true, "detail": "4.0/5"}, {"label": "상승여력", "ok": true, "detail": "+49%"}, {"label": "어닝 서프라이즈", "ok": true, "detail": "+ "}, {"label": "시장 강세", "ok": true, "detail": "강세"}, {"label": "과열 아님(회전율)", "ok": true, "detail": "3.39% (환산) vs 평균 2.17% (보류 3배↑)"}, {"label": "돌파(전고점)", "ok": false, "detail": "고점 304,000"}, {"label": "거래량 급증", "ok": false, "detail": "5,311,497 (환산) vs 평균 3,404,288"}, {"label": "회전율 급증", "ok": true, "detail": "3.39% (환산) vs 평균 2.17%"}, {"label": "RSI", "ok": true, "detail": "48"}, {"label": "눌림목 도달", "ok": true, "detail": "지정가 232,280 (현재 221,000)"}]}
@@ -9,5 +9,5 @@
"max_drawdown": 0.0,
"last_exit": {},
"created_at": "2026-06-11T09:00:01.943420+09:00",
"updated_at": "2026-06-11T11:20:02.310478+09:00"
"updated_at": "2026-06-11T15:25:07.396835+09:00"
}
@@ -1,13 +1,35 @@
{
"cash": 100000000,
"cash": 95790868.725,
"initial": 100000000,
"positions": {},
"positions": {
"035420": {
"code": "035420",
"name": "NAVER",
"sources": [
"interest"
],
"qty": 19,
"entry_price": 221500,
"entry_at": "2026-06-11T12:45:02.424478+09:00",
"stop": 195800,
"target": 272900,
"peak": 224000,
"trailing_on": false,
"scaled_out": false,
"entry_path": "pullback",
"entry_reason": "눌림목 지정가 232,280 도달",
"cur_price": 222000,
"tranches": 1,
"tranche_value": 4309338.521400778,
"last_add_price": 221500
}
},
"realized_pnl": 0.0,
"closed_trades": 0,
"wins": 0,
"peak_equity": 100000000,
"max_drawdown": 0.0,
"peak_equity": 100046868.725,
"max_drawdown": 0.0004747774778495448,
"last_exit": {},
"created_at": "2026-06-11T09:00:01.943430+09:00",
"updated_at": "2026-06-11T11:20:02.313039+09:00"
"updated_at": "2026-06-11T15:25:07.399194+09:00"
}
@@ -0,0 +1 @@
{"ts": "2026-06-11T12:45:02.424482+09:00", "side": "BUY", "code": "035420", "name": "NAVER", "price": 221500, "qty": 19, "cost": 4209131, "path": "pullback", "reason": "눌림목 지정가 232,280 도달", "stop": 195800, "target": 272900, "signals": [{"label": "추세(20일선 위)", "ok": true, "detail": "221,000 vs 218,048"}, {"label": "정배열(5>20)", "ok": true, "detail": "256,000 / 218,048"}, {"label": "추세 기울기(20일선↑)", "ok": true, "detail": "우상향"}, {"label": "중기 정배열(5>60)", "ok": true, "detail": "256,000 / 215,415"}, {"label": "상대강도(시장대비)", "ok": true, "detail": "+3.8%p"}, {"label": "수급(5일 외/기)", "ok": true, "detail": "외 -132 · 기 +1,200 (천주)"}, {"label": "투자의견", "ok": true, "detail": "4.0/5"}, {"label": "상승여력", "ok": true, "detail": "+49%"}, {"label": "어닝 서프라이즈", "ok": true, "detail": "+ "}, {"label": "시장 강세", "ok": true, "detail": "강세"}, {"label": "과열 아님(회전율)", "ok": true, "detail": "3.39% (환산) vs 평균 2.17% (보류 3배↑)"}, {"label": "돌파(전고점)", "ok": false, "detail": "고점 304,000"}, {"label": "거래량 급증", "ok": false, "detail": "5,311,497 (환산) vs 평균 3,404,288"}, {"label": "회전율 급증", "ok": true, "detail": "3.39% (환산) vs 평균 2.17%"}, {"label": "RSI", "ok": true, "detail": "48"}, {"label": "눌림목 도달", "ok": true, "detail": "지정가 232,280 (현재 221,000)"}]}
@@ -1,13 +1,35 @@
{
"cash": 100000000,
"cash": 95790868.725,
"initial": 100000000,
"positions": {},
"positions": {
"035420": {
"code": "035420",
"name": "NAVER",
"sources": [
"interest"
],
"qty": 19,
"entry_price": 221500,
"entry_at": "2026-06-11T12:45:02.427828+09:00",
"stop": 195800,
"target": 260050,
"peak": 224000,
"trailing_on": false,
"scaled_out": false,
"entry_path": "pullback",
"entry_reason": "눌림목 지정가 232,280 도달",
"cur_price": 222000,
"tranches": 1,
"tranche_value": 4309338.521400778,
"last_add_price": 221500
}
},
"realized_pnl": 0.0,
"closed_trades": 0,
"wins": 0,
"peak_equity": 100000000,
"max_drawdown": 0.0,
"peak_equity": 100046868.725,
"max_drawdown": 0.0004747774778495448,
"last_exit": {},
"created_at": "2026-06-11T09:00:01.943440+09:00",
"updated_at": "2026-06-11T11:20:02.315363+09:00"
"updated_at": "2026-06-11T15:25:07.401623+09:00"
}
@@ -0,0 +1 @@
{"ts": "2026-06-11T12:45:02.427830+09:00", "side": "BUY", "code": "035420", "name": "NAVER", "price": 221500, "qty": 19, "cost": 4209131, "path": "pullback", "reason": "눌림목 지정가 232,280 도달", "stop": 195800, "target": 260050, "signals": [{"label": "추세(20일선 위)", "ok": true, "detail": "221,000 vs 218,048"}, {"label": "정배열(5>20)", "ok": true, "detail": "256,000 / 218,048"}, {"label": "추세 기울기(20일선↑)", "ok": true, "detail": "우상향"}, {"label": "중기 정배열(5>60)", "ok": true, "detail": "256,000 / 215,415"}, {"label": "상대강도(시장대비)", "ok": true, "detail": "+3.8%p"}, {"label": "수급(5일 외/기)", "ok": true, "detail": "외 -132 · 기 +1,200 (천주)"}, {"label": "투자의견", "ok": true, "detail": "4.0/5"}, {"label": "상승여력", "ok": true, "detail": "+49%"}, {"label": "어닝 서프라이즈", "ok": true, "detail": "+ "}, {"label": "시장 강세", "ok": true, "detail": "강세"}, {"label": "과열 아님(회전율)", "ok": true, "detail": "3.39% (환산) vs 평균 2.17% (보류 3배↑)"}, {"label": "돌파(전고점)", "ok": false, "detail": "고점 304,000"}, {"label": "거래량 급증", "ok": false, "detail": "5,311,497 (환산) vs 평균 3,404,288"}, {"label": "회전율 급증", "ok": true, "detail": "3.39% (환산) vs 평균 2.17%"}, {"label": "RSI", "ok": true, "detail": "48"}, {"label": "눌림목 도달", "ok": true, "detail": "지정가 232,280 (현재 221,000)"}]}
@@ -9,5 +9,5 @@
"max_drawdown": 0.0,
"last_exit": {},
"created_at": "2026-06-11T09:00:01.943450+09:00",
"updated_at": "2026-06-11T11:20:02.317659+09:00"
"updated_at": "2026-06-11T15:25:07.403888+09:00"
}
@@ -9,5 +9,5 @@
"max_drawdown": 0.0,
"last_exit": {},
"created_at": "2026-06-11T09:00:01.943460+09:00",
"updated_at": "2026-06-11T11:20:02.319824+09:00"
"updated_at": "2026-06-11T15:25:07.406120+09:00"
}
@@ -9,5 +9,5 @@
"max_drawdown": 0.0,
"last_exit": {},
"created_at": "2026-06-11T09:00:01.943470+09:00",
"updated_at": "2026-06-11T11:20:02.321996+09:00"
"updated_at": "2026-06-11T15:25:07.408165+09:00"
}
@@ -9,5 +9,5 @@
"max_drawdown": 0.0,
"last_exit": {},
"created_at": "2026-06-11T09:00:01.943480+09:00",
"updated_at": "2026-06-11T11:20:02.324000+09:00"
"updated_at": "2026-06-11T15:25:07.410164+09:00"
}
@@ -9,5 +9,5 @@
"max_drawdown": 0.0,
"last_exit": {},
"created_at": "2026-06-11T09:00:01.943216+09:00",
"updated_at": "2026-06-11T11:20:01.466664+09:00"
"updated_at": "2026-06-11T15:25:06.530101+09:00"
}
@@ -9,5 +9,5 @@
"max_drawdown": 0.0,
"last_exit": {},
"created_at": "2026-06-11T09:00:01.943489+09:00",
"updated_at": "2026-06-11T11:20:02.325961+09:00"
"updated_at": "2026-06-11T15:25:07.412089+09:00"
}
@@ -9,5 +9,5 @@
"max_drawdown": 0.0,
"last_exit": {},
"created_at": "2026-06-11T09:00:01.943499+09:00",
"updated_at": "2026-06-11T11:20:02.327802+09:00"
"updated_at": "2026-06-11T15:25:07.413928+09:00"
}
@@ -9,5 +9,5 @@
"max_drawdown": 0.0,
"last_exit": {},
"created_at": "2026-06-11T09:00:01.943509+09:00",
"updated_at": "2026-06-11T11:20:02.329561+09:00"
"updated_at": "2026-06-11T15:25:07.415765+09:00"
}
@@ -9,5 +9,5 @@
"max_drawdown": 0.0,
"last_exit": {},
"created_at": "2026-06-11T09:00:01.943518+09:00",
"updated_at": "2026-06-11T11:20:02.331301+09:00"
"updated_at": "2026-06-11T15:25:07.417573+09:00"
}
@@ -9,5 +9,5 @@
"max_drawdown": 0.0,
"last_exit": {},
"created_at": "2026-06-11T09:00:01.943528+09:00",
"updated_at": "2026-06-11T11:20:02.332925+09:00"
"updated_at": "2026-06-11T15:25:07.419366+09:00"
}
@@ -9,5 +9,5 @@
"max_drawdown": 0.0,
"last_exit": {},
"created_at": "2026-06-11T09:00:01.943540+09:00",
"updated_at": "2026-06-11T11:20:02.334560+09:00"
"updated_at": "2026-06-11T15:25:07.421149+09:00"
}
@@ -9,5 +9,5 @@
"max_drawdown": 0.0,
"last_exit": {},
"created_at": "2026-06-11T09:00:01.943551+09:00",
"updated_at": "2026-06-11T11:20:02.336195+09:00"
"updated_at": "2026-06-11T15:25:07.422820+09:00"
}
@@ -9,5 +9,5 @@
"max_drawdown": 0.0,
"last_exit": {},
"created_at": "2026-06-11T09:00:01.943560+09:00",
"updated_at": "2026-06-11T11:20:02.337809+09:00"
"updated_at": "2026-06-11T15:25:07.424521+09:00"
}
@@ -9,5 +9,5 @@
"max_drawdown": 0.0,
"last_exit": {},
"created_at": "2026-06-11T09:00:01.943570+09:00",
"updated_at": "2026-06-11T11:20:02.339489+09:00"
"updated_at": "2026-06-11T15:25:07.426135+09:00"
}
@@ -9,5 +9,5 @@
"max_drawdown": 0.0,
"last_exit": {},
"created_at": "2026-06-11T09:00:01.943580+09:00",
"updated_at": "2026-06-11T11:20:02.341022+09:00"
"updated_at": "2026-06-11T15:25:07.427703+09:00"
}
@@ -9,5 +9,5 @@
"max_drawdown": 0.0,
"last_exit": {},
"created_at": "2026-06-11T09:00:01.943227+09:00",
"updated_at": "2026-06-11T11:20:01.469146+09:00"
"updated_at": "2026-06-11T15:25:06.533738+09:00"
}
@@ -18,7 +18,7 @@
"scaled_out": false,
"entry_path": "pullback",
"entry_reason": "눌림목 지정가 232,280 도달",
"cur_price": 221000,
"cur_price": 222000,
"tranches": 1,
"tranche_value": 6250000.0,
"last_add_price": 226000
@@ -28,8 +28,8 @@
"closed_trades": 0,
"wins": 0,
"peak_equity": 100000000,
"max_drawdown": 0.0013591529999999702,
"max_drawdown": 0.0017641529999999702,
"last_exit": {},
"created_at": "2026-06-11T09:00:01.943590+09:00",
"updated_at": "2026-06-11T11:20:02.342568+09:00"
"updated_at": "2026-06-11T15:25:07.429284+09:00"
}
@@ -9,5 +9,5 @@
"max_drawdown": 0.0,
"last_exit": {},
"created_at": "2026-06-11T09:00:01.943599+09:00",
"updated_at": "2026-06-11T11:20:02.344126+09:00"
"updated_at": "2026-06-11T15:25:07.430807+09:00"
}
@@ -18,7 +18,7 @@
"scaled_out": false,
"entry_path": "pullback",
"entry_reason": "눌림목 지정가 232,280 도달",
"cur_price": 221000,
"cur_price": 222000,
"tranches": 1,
"tranche_value": 6250000.0,
"last_add_price": 226000
@@ -28,8 +28,8 @@
"closed_trades": 0,
"wins": 0,
"peak_equity": 100000000,
"max_drawdown": 0.0013591529999999702,
"max_drawdown": 0.0017641529999999702,
"last_exit": {},
"created_at": "2026-06-11T09:00:01.943609+09:00",
"updated_at": "2026-06-11T11:20:02.345749+09:00"
"updated_at": "2026-06-11T15:25:07.432382+09:00"
}
@@ -9,5 +9,5 @@
"max_drawdown": 0.0,
"last_exit": {},
"created_at": "2026-06-11T09:00:01.943619+09:00",
"updated_at": "2026-06-11T11:20:02.347238+09:00"
"updated_at": "2026-06-11T15:25:07.433821+09:00"
}
@@ -18,7 +18,7 @@
"scaled_out": false,
"entry_path": "pullback",
"entry_reason": "눌림목 지정가 232,280 도달",
"cur_price": 221000,
"cur_price": 222000,
"tranches": 1,
"tranche_value": 6250000.0,
"last_add_price": 226000
@@ -28,8 +28,8 @@
"closed_trades": 0,
"wins": 0,
"peak_equity": 100000000,
"max_drawdown": 0.0013591529999999702,
"max_drawdown": 0.0017641529999999702,
"last_exit": {},
"created_at": "2026-06-11T09:00:01.943633+09:00",
"updated_at": "2026-06-11T11:20:02.348704+09:00"
"updated_at": "2026-06-11T15:25:07.435257+09:00"
}
@@ -9,5 +9,5 @@
"max_drawdown": 0.0,
"last_exit": {},
"created_at": "2026-06-11T09:00:01.943643+09:00",
"updated_at": "2026-06-11T11:20:02.350094+09:00"
"updated_at": "2026-06-11T15:25:07.436643+09:00"
}
@@ -9,5 +9,5 @@
"max_drawdown": 0.0,
"last_exit": {},
"created_at": "2026-06-11T09:00:01.943653+09:00",
"updated_at": "2026-06-11T11:20:02.351439+09:00"
"updated_at": "2026-06-11T15:25:07.438026+09:00"
}
@@ -9,5 +9,5 @@
"max_drawdown": 0.0,
"last_exit": {},
"created_at": "2026-06-11T09:00:01.943663+09:00",
"updated_at": "2026-06-11T11:20:02.352795+09:00"
"updated_at": "2026-06-11T15:25:07.439417+09:00"
}
@@ -18,7 +18,7 @@
"scaled_out": false,
"entry_path": "pullback",
"entry_reason": "눌림목 지정가 232,280 도달",
"cur_price": 221000,
"cur_price": 222000,
"tranches": 1,
"tranche_value": 3741721.8543046354,
"last_add_price": 226000
@@ -28,8 +28,8 @@
"closed_trades": 0,
"wins": 0,
"peak_equity": 100000000,
"max_drawdown": 0.0008054240000000596,
"max_drawdown": 0.0010454240000000595,
"last_exit": {},
"created_at": "2026-06-11T09:00:01.943673+09:00",
"updated_at": "2026-06-11T11:20:02.354131+09:00"
"updated_at": "2026-06-11T15:25:07.440747+09:00"
}
@@ -9,5 +9,5 @@
"max_drawdown": 0.0,
"last_exit": {},
"created_at": "2026-06-11T09:00:01.943683+09:00",
"updated_at": "2026-06-11T11:20:02.355430+09:00"
"updated_at": "2026-06-11T15:25:07.442090+09:00"
}
@@ -9,5 +9,5 @@
"max_drawdown": 0.0,
"last_exit": {},
"created_at": "2026-06-11T09:00:01.943238+09:00",
"updated_at": "2026-06-11T11:20:01.471616+09:00"
"updated_at": "2026-06-11T15:25:06.536744+09:00"
}
@@ -9,5 +9,5 @@
"max_drawdown": 0.0,
"last_exit": {},
"created_at": "2026-06-11T09:00:01.943693+09:00",
"updated_at": "2026-06-11T11:20:02.356726+09:00"
"updated_at": "2026-06-11T15:25:07.443439+09:00"
}
@@ -9,5 +9,5 @@
"max_drawdown": 0.0,
"last_exit": {},
"created_at": "2026-06-11T09:00:01.943703+09:00",
"updated_at": "2026-06-11T11:20:02.358010+09:00"
"updated_at": "2026-06-11T15:25:07.444730+09:00"
}
@@ -9,5 +9,5 @@
"max_drawdown": 0.0,
"last_exit": {},
"created_at": "2026-06-11T09:00:01.943713+09:00",
"updated_at": "2026-06-11T11:20:02.359272+09:00"
"updated_at": "2026-06-11T15:25:07.445992+09:00"
}
@@ -9,5 +9,5 @@
"max_drawdown": 0.0,
"last_exit": {},
"created_at": "2026-06-11T09:00:01.943722+09:00",
"updated_at": "2026-06-11T11:20:02.360501+09:00"
"updated_at": "2026-06-11T15:25:07.447250+09:00"
}
@@ -9,5 +9,5 @@
"max_drawdown": 0.0,
"last_exit": {},
"created_at": "2026-06-11T09:00:01.943732+09:00",
"updated_at": "2026-06-11T11:20:02.361737+09:00"
"updated_at": "2026-06-11T15:25:07.448510+09:00"
}
@@ -9,5 +9,5 @@
"max_drawdown": 0.0,
"last_exit": {},
"created_at": "2026-06-11T09:00:01.943741+09:00",
"updated_at": "2026-06-11T11:20:02.362969+09:00"
"updated_at": "2026-06-11T15:25:07.449695+09:00"
}
@@ -9,5 +9,5 @@
"max_drawdown": 0.0,
"last_exit": {},
"created_at": "2026-06-11T09:00:01.943751+09:00",
"updated_at": "2026-06-11T11:20:02.364127+09:00"
"updated_at": "2026-06-11T15:25:07.450870+09:00"
}
@@ -9,5 +9,5 @@
"max_drawdown": 0.0,
"last_exit": {},
"created_at": "2026-06-11T09:00:01.943761+09:00",
"updated_at": "2026-06-11T11:20:02.365282+09:00"
"updated_at": "2026-06-11T15:25:07.452053+09:00"
}
@@ -9,5 +9,5 @@
"max_drawdown": 0.0,
"last_exit": {},
"created_at": "2026-06-11T09:00:01.943771+09:00",
"updated_at": "2026-06-11T11:20:02.366441+09:00"
"updated_at": "2026-06-11T15:25:07.453242+09:00"
}
@@ -9,5 +9,5 @@
"max_drawdown": 0.0,
"last_exit": {},
"created_at": "2026-06-11T09:00:01.943780+09:00",
"updated_at": "2026-06-11T11:20:02.367584+09:00"
"updated_at": "2026-06-11T15:25:07.454393+09:00"
}
@@ -9,5 +9,5 @@
"max_drawdown": 0.0,
"last_exit": {},
"created_at": "2026-06-11T09:00:01.943248+09:00",
"updated_at": "2026-06-11T11:20:01.473813+09:00"
"updated_at": "2026-06-11T15:25:06.539716+09:00"
}
@@ -9,5 +9,5 @@
"max_drawdown": 0.0,
"last_exit": {},
"created_at": "2026-06-11T09:00:01.943790+09:00",
"updated_at": "2026-06-11T11:20:02.368722+09:00"
"updated_at": "2026-06-11T15:25:07.455538+09:00"
}
@@ -9,5 +9,5 @@
"max_drawdown": 0.0,
"last_exit": {},
"created_at": "2026-06-11T09:00:01.943802+09:00",
"updated_at": "2026-06-11T11:20:02.369915+09:00"
"updated_at": "2026-06-11T15:25:07.456761+09:00"
}
@@ -18,7 +18,7 @@
"scaled_out": false,
"entry_path": "pullback",
"entry_reason": "눌림목 지정가 219,919 도달",
"cur_price": 221000,
"cur_price": 222000,
"tranches": 1,
"tranche_value": 6250000.0,
"last_add_price": 220500
@@ -39,7 +39,7 @@
"scaled_out": false,
"entry_path": "pullback",
"entry_reason": "눌림목 지정가 96,991 도달",
"cur_price": 91000,
"cur_price": 92800,
"tranches": 1,
"tranche_value": 5607543.004772153,
"last_add_price": 88600
@@ -49,8 +49,8 @@
"closed_trades": 0,
"wins": 0,
"peak_equity": 100454286.63000001,
"max_drawdown": 0.0028953468264751934,
"max_drawdown": 0.0037524531072368034,
"last_exit": {},
"created_at": "2026-06-11T09:00:01.943812+09:00",
"updated_at": "2026-06-11T11:20:02.371103+09:00"
"updated_at": "2026-06-11T15:25:07.457973+09:00"
}
@@ -9,5 +9,5 @@
"max_drawdown": 0.0,
"last_exit": {},
"created_at": "2026-06-11T09:00:01.943822+09:00",
"updated_at": "2026-06-11T11:20:02.372328+09:00"
"updated_at": "2026-06-11T15:25:07.459214+09:00"
}
@@ -18,7 +18,7 @@
"scaled_out": false,
"entry_path": "pullback",
"entry_reason": "눌림목 지정가 219,919 도달",
"cur_price": 221000,
"cur_price": 222000,
"tranches": 1,
"tranche_value": 6250000.0,
"last_add_price": 220500
@@ -39,7 +39,7 @@
"scaled_out": false,
"entry_path": "pullback",
"entry_reason": "눌림목 지정가 96,991 도달",
"cur_price": 91000,
"cur_price": 92800,
"tranches": 1,
"tranche_value": 5607543.004772153,
"last_add_price": 88600
@@ -49,8 +49,8 @@
"closed_trades": 0,
"wins": 0,
"peak_equity": 100454286.63000001,
"max_drawdown": 0.0028953468264751934,
"max_drawdown": 0.0037524531072368034,
"last_exit": {},
"created_at": "2026-06-11T09:00:01.943832+09:00",
"updated_at": "2026-06-11T11:20:02.373529+09:00"
"updated_at": "2026-06-11T15:25:07.460431+09:00"
}
@@ -9,5 +9,5 @@
"max_drawdown": 0.0,
"last_exit": {},
"created_at": "2026-06-11T09:00:01.943843+09:00",
"updated_at": "2026-06-11T11:20:02.374735+09:00"
"updated_at": "2026-06-11T15:25:07.461661+09:00"
}
@@ -18,7 +18,7 @@
"scaled_out": false,
"entry_path": "pullback",
"entry_reason": "눌림목 지정가 219,919 도달",
"cur_price": 221000,
"cur_price": 222000,
"tranches": 1,
"tranche_value": 6250000.0,
"last_add_price": 220500
@@ -39,7 +39,7 @@
"scaled_out": false,
"entry_path": "pullback",
"entry_reason": "눌림목 지정가 96,991 도달",
"cur_price": 91000,
"cur_price": 92800,
"tranches": 1,
"tranche_value": 5607543.004772153,
"last_add_price": 88600
@@ -49,8 +49,8 @@
"closed_trades": 0,
"wins": 0,
"peak_equity": 100454286.63000001,
"max_drawdown": 0.0028953468264751934,
"max_drawdown": 0.0037524531072368034,
"last_exit": {},
"created_at": "2026-06-11T09:00:01.943852+09:00",
"updated_at": "2026-06-11T11:20:02.375923+09:00"
"updated_at": "2026-06-11T15:25:07.462900+09:00"
}
@@ -9,5 +9,5 @@
"max_drawdown": 0.0,
"last_exit": {},
"created_at": "2026-06-11T09:00:01.943862+09:00",
"updated_at": "2026-06-11T11:20:02.377134+09:00"
"updated_at": "2026-06-11T15:25:07.464153+09:00"
}
@@ -18,7 +18,7 @@
"scaled_out": false,
"entry_path": "pullback",
"entry_reason": "눌림목 지정가 219,919 도달",
"cur_price": 221000,
"cur_price": 222000,
"tranches": 1,
"tranche_value": 4463562.753036438,
"last_add_price": 220500
@@ -39,7 +39,7 @@
"scaled_out": false,
"entry_path": "pullback",
"entry_reason": "눌림목 지정가 96,991 도달",
"cur_price": 91000,
"cur_price": 92800,
"tranches": 1,
"tranche_value": 2803778.9212341774,
"last_add_price": 88600
@@ -49,8 +49,8 @@
"closed_trades": 0,
"wins": 0,
"peak_equity": 100263776.51,
"max_drawdown": 0.0017997526752047133,
"max_drawdown": 0.0023153925383694886,
"last_exit": {},
"created_at": "2026-06-11T09:00:01.943872+09:00",
"updated_at": "2026-06-11T11:20:02.378346+09:00"
"updated_at": "2026-06-11T15:25:07.465388+09:00"
}
@@ -9,5 +9,5 @@
"max_drawdown": 0.0,
"last_exit": {},
"created_at": "2026-06-11T09:00:01.943883+09:00",
"updated_at": "2026-06-11T11:20:02.379559+09:00"
"updated_at": "2026-06-11T15:25:07.466634+09:00"
}
@@ -9,5 +9,5 @@
"max_drawdown": 0.0,
"last_exit": {},
"created_at": "2026-06-11T09:00:01.943259+09:00",
"updated_at": "2026-06-11T11:20:01.475995+09:00"
"updated_at": "2026-06-11T15:25:06.542556+09:00"
}
@@ -18,7 +18,7 @@
"scaled_out": false,
"entry_path": "pullback",
"entry_reason": "눌림목 지정가 219,919 도달",
"cur_price": 221000,
"cur_price": 222000,
"tranches": 1,
"tranche_value": 4463562.753036438,
"last_add_price": 220500
@@ -39,7 +39,7 @@
"scaled_out": false,
"entry_path": "pullback",
"entry_reason": "눌림목 지정가 96,991 도달",
"cur_price": 91000,
"cur_price": 92800,
"tranches": 1,
"tranche_value": 2803778.9212341774,
"last_add_price": 88600
@@ -49,8 +49,8 @@
"closed_trades": 0,
"wins": 0,
"peak_equity": 100263776.51,
"max_drawdown": 0.0017997526752047133,
"max_drawdown": 0.0023153925383694886,
"last_exit": {},
"created_at": "2026-06-11T09:00:01.943893+09:00",
"updated_at": "2026-06-11T11:20:02.380743+09:00"
"updated_at": "2026-06-11T15:25:07.467855+09:00"
}
@@ -9,5 +9,5 @@
"max_drawdown": 0.0,
"last_exit": {},
"created_at": "2026-06-11T09:00:01.943903+09:00",
"updated_at": "2026-06-11T11:20:02.381985+09:00"
"updated_at": "2026-06-11T15:25:07.469116+09:00"
}
@@ -18,7 +18,7 @@
"scaled_out": false,
"entry_path": "pullback",
"entry_reason": "눌림목 지정가 219,919 도달",
"cur_price": 221000,
"cur_price": 222000,
"tranches": 1,
"tranche_value": 4463562.753036438,
"last_add_price": 220500
@@ -39,7 +39,7 @@
"scaled_out": false,
"entry_path": "pullback",
"entry_reason": "눌림목 지정가 96,991 도달",
"cur_price": 91000,
"cur_price": 92800,
"tranches": 1,
"tranche_value": 2803778.9212341774,
"last_add_price": 88600
@@ -49,8 +49,8 @@
"closed_trades": 0,
"wins": 0,
"peak_equity": 100263776.51,
"max_drawdown": 0.0017997526752047133,
"max_drawdown": 0.0023153925383694886,
"last_exit": {},
"created_at": "2026-06-11T09:00:01.943912+09:00",
"updated_at": "2026-06-11T11:20:02.383177+09:00"
"updated_at": "2026-06-11T15:25:07.470341+09:00"
}
@@ -9,5 +9,5 @@
"max_drawdown": 0.0,
"last_exit": {},
"created_at": "2026-06-11T09:00:01.943922+09:00",
"updated_at": "2026-06-11T11:20:02.384385+09:00"
"updated_at": "2026-06-11T15:25:07.471570+09:00"
}
@@ -18,7 +18,7 @@
"scaled_out": false,
"entry_path": "pullback",
"entry_reason": "눌림목 지정가 219,919 도달",
"cur_price": 221000,
"cur_price": 222000,
"tranches": 1,
"tranche_value": 4463562.753036438,
"last_add_price": 220500
@@ -39,7 +39,7 @@
"scaled_out": false,
"entry_path": "pullback",
"entry_reason": "눌림목 지정가 96,991 도달",
"cur_price": 91000,
"cur_price": 92800,
"tranches": 1,
"tranche_value": 2803778.9212341774,
"last_add_price": 88600
@@ -49,8 +49,8 @@
"closed_trades": 0,
"wins": 0,
"peak_equity": 100263776.51,
"max_drawdown": 0.0017997526752047133,
"max_drawdown": 0.0023153925383694886,
"last_exit": {},
"created_at": "2026-06-11T09:00:01.943932+09:00",
"updated_at": "2026-06-11T11:20:02.385575+09:00"
"updated_at": "2026-06-11T15:25:07.472796+09:00"
}
@@ -9,5 +9,5 @@
"max_drawdown": 0.0,
"last_exit": {},
"created_at": "2026-06-11T09:00:01.943941+09:00",
"updated_at": "2026-06-11T11:20:02.386784+09:00"
"updated_at": "2026-06-11T15:25:07.474083+09:00"
}
@@ -18,7 +18,7 @@
"scaled_out": false,
"entry_path": "pullback",
"entry_reason": "눌림목 지정가 219,919 도달",
"cur_price": 221000,
"cur_price": 222000,
"tranches": 1,
"tranche_value": 4463562.753036438,
"last_add_price": 220500
@@ -39,7 +39,7 @@
"scaled_out": false,
"entry_path": "pullback",
"entry_reason": "눌림목 지정가 96,991 도달",
"cur_price": 91000,
"cur_price": 92800,
"tranches": 1,
"tranche_value": 2803778.9212341774,
"last_add_price": 88600
@@ -49,8 +49,8 @@
"closed_trades": 0,
"wins": 0,
"peak_equity": 100263776.51,
"max_drawdown": 0.0017997526752047133,
"max_drawdown": 0.0023153925383694886,
"last_exit": {},
"created_at": "2026-06-11T09:00:01.943951+09:00",
"updated_at": "2026-06-11T11:20:02.387970+09:00"
"updated_at": "2026-06-11T15:25:07.475332+09:00"
}
@@ -9,5 +9,5 @@
"max_drawdown": 0.0,
"last_exit": {},
"created_at": "2026-06-11T09:00:01.943960+09:00",
"updated_at": "2026-06-11T11:20:02.389225+09:00"
"updated_at": "2026-06-11T15:25:07.476584+09:00"
}
@@ -18,7 +18,7 @@
"scaled_out": false,
"entry_path": "pullback",
"entry_reason": "눌림목 지정가 219,919 도달",
"cur_price": 221000,
"cur_price": 222000,
"tranches": 1,
"tranche_value": 4463562.753036438,
"last_add_price": 220500
@@ -39,7 +39,7 @@
"scaled_out": false,
"entry_path": "pullback",
"entry_reason": "눌림목 지정가 96,991 도달",
"cur_price": 91000,
"cur_price": 92800,
"tranches": 1,
"tranche_value": 2803778.9212341774,
"last_add_price": 88600
@@ -49,8 +49,8 @@
"closed_trades": 0,
"wins": 0,
"peak_equity": 100263776.51,
"max_drawdown": 0.0017997526752047133,
"max_drawdown": 0.0023153925383694886,
"last_exit": {},
"created_at": "2026-06-11T09:00:01.943970+09:00",
"updated_at": "2026-06-11T11:20:02.390424+09:00"
"updated_at": "2026-06-11T15:25:07.477814+09:00"
}
@@ -1,13 +1,35 @@
{
"cash": 100000000,
"cash": 95790868.725,
"initial": 100000000,
"positions": {},
"positions": {
"035420": {
"code": "035420",
"name": "NAVER",
"sources": [
"interest"
],
"qty": 19,
"entry_price": 221500,
"entry_at": "2026-06-11T12:45:02.509411+09:00",
"stop": 195800,
"target": 272900,
"peak": 224000,
"trailing_on": false,
"scaled_out": false,
"entry_path": "pullback",
"entry_reason": "눌림목 지정가 232,280 도달",
"cur_price": 222000,
"tranches": 1,
"tranche_value": 4309338.521400778,
"last_add_price": 221500
}
},
"realized_pnl": 0.0,
"closed_trades": 0,
"wins": 0,
"peak_equity": 100000000,
"max_drawdown": 0.0,
"peak_equity": 100046868.725,
"max_drawdown": 0.0004747774778495448,
"last_exit": {},
"created_at": "2026-06-11T09:00:01.943979+09:00",
"updated_at": "2026-06-11T11:20:02.391632+09:00"
"updated_at": "2026-06-11T15:25:07.479069+09:00"
}
@@ -0,0 +1 @@
{"ts": "2026-06-11T12:45:02.509412+09:00", "side": "BUY", "code": "035420", "name": "NAVER", "price": 221500, "qty": 19, "cost": 4209131, "path": "pullback", "reason": "눌림목 지정가 232,280 도달", "stop": 195800, "target": 272900, "signals": [{"label": "추세(20일선 위)", "ok": true, "detail": "221,000 vs 218,048"}, {"label": "정배열(5>20)", "ok": true, "detail": "256,000 / 218,048"}, {"label": "추세 기울기(20일선↑)", "ok": true, "detail": "우상향"}, {"label": "중기 정배열(5>60)", "ok": true, "detail": "256,000 / 215,415"}, {"label": "상대강도(시장대비)", "ok": true, "detail": "+3.8%p"}, {"label": "수급(5일 외/기)", "ok": true, "detail": "외 -132 · 기 +1,200 (천주)"}, {"label": "투자의견", "ok": true, "detail": "4.0/5"}, {"label": "상승여력", "ok": true, "detail": "+49%"}, {"label": "어닝 서프라이즈", "ok": true, "detail": "+ "}, {"label": "시장 강세", "ok": true, "detail": "강세"}, {"label": "과열 아님(회전율)", "ok": true, "detail": "3.39% (환산) vs 평균 2.17% (보류 3배↑)"}, {"label": "돌파(전고점)", "ok": false, "detail": "고점 304,000"}, {"label": "거래량 급증", "ok": false, "detail": "5,311,497 (환산) vs 평균 3,404,288"}, {"label": "회전율 급증", "ok": true, "detail": "3.39% (환산) vs 평균 2.17%"}, {"label": "RSI", "ok": true, "detail": "48"}, {"label": "눌림목 도달", "ok": true, "detail": "지정가 232,280 (현재 221,000)"}]}
@@ -9,5 +9,5 @@
"max_drawdown": 0.0,
"last_exit": {},
"created_at": "2026-06-11T09:00:01.943269+09:00",
"updated_at": "2026-06-11T11:20:01.478170+09:00"
"updated_at": "2026-06-11T15:25:06.545085+09:00"
}
@@ -18,7 +18,7 @@
"scaled_out": false,
"entry_path": "pullback",
"entry_reason": "눌림목 지정가 232,280 도달",
"cur_price": 221000,
"cur_price": 222000,
"tranches": 1,
"tranche_value": 4463562.753036438,
"last_add_price": 220500
@@ -39,7 +39,7 @@
"scaled_out": false,
"entry_path": "pullback",
"entry_reason": "눌림목 지정가 103,828 도달",
"cur_price": 91000,
"cur_price": 92800,
"tranches": 1,
"tranche_value": 2803778.9212341774,
"last_add_price": 88600
@@ -49,8 +49,8 @@
"closed_trades": 0,
"wins": 0,
"peak_equity": 100263776.51,
"max_drawdown": 0.0017997526752047133,
"max_drawdown": 0.0023153925383694886,
"last_exit": {},
"created_at": "2026-06-11T09:00:01.943989+09:00",
"updated_at": "2026-06-11T11:20:02.392814+09:00"
"updated_at": "2026-06-11T15:25:07.480320+09:00"
}
@@ -9,5 +9,5 @@
"max_drawdown": 0.0,
"last_exit": {},
"created_at": "2026-06-11T09:00:01.943999+09:00",
"updated_at": "2026-06-11T11:20:02.393989+09:00"
"updated_at": "2026-06-11T15:25:07.481515+09:00"
}
@@ -9,5 +9,5 @@
"max_drawdown": 0.0,
"last_exit": {},
"created_at": "2026-06-11T09:00:01.944008+09:00",
"updated_at": "2026-06-11T11:20:02.395158+09:00"
"updated_at": "2026-06-11T15:25:07.482690+09:00"
}

Some files were not shown because too many files have changed in this diff Show More