feat: Enhance trading system with new permanent subscription features and order book management

Changes:
- Added a new API endpoint for managing permanent subscriptions, allowing users to enable or disable subscriptions dynamically.
- Implemented a function to fill candle data from Kiwoom, ensuring that only relevant data is inserted into the database.
- Introduced a mechanism to handle master subscription states, improving the management of subscription statuses.
- Updated the database schema to include new fields for managing subscription states and order book filtering.

Impact:
- These enhancements improve the flexibility and reliability of the trading system, allowing for better management of subscriptions and order book data, while reducing the risk of data inconsistencies.

히스토리 align 제거 븅신같은 초기설계 아예 제거
진입모드에 구멍메움
호가진입을 켜도 호가가 안들어올때 호가 안보고 그냥 사버림
This commit is contained in:
Your Name
2026-08-15 23:01:14 +09:00
parent 4a18ce2697
commit 36a3e2b4a1
94 changed files with 6368 additions and 1639 deletions

View File

@@ -336,7 +336,7 @@
<th>종목</th><th>매수시각</th><th>매도시각</th>
<th>매수가</th><th>매도가</th><th>수량</th>
<th>손익(원)</th><th>수익률%</th><th>누적손익</th><th>누적%</th>
<th>보유(분)</th><th>체결디버그</th><th title="매수 시점 호가 (M:L3잔량비 W:전체잔량비 OR)">매수호가</th><th title="매도 시점 호가 (M:L3잔량비 W:전체잔량비 OR)">매도호가</th><th>매도사유</th>
<th>보유(분)</th><th>체결디버그</th><th title="【살 때】 녹=괜찮음 · 노랑=숫자만/기록없음 · 빨강=간격큼/살힘약함/팔대기많음. 가격간격=낮을수록 좋음, 살힘=높을수록 좋음(1≈균형).">매수호가<br><span style="font-size:9px;font-weight:400;opacity:.7">녹OK · 노랑참고 · 빨강나쁨</span></th><th title="【팔 때】 녹=수급OK · 노랑=숫자만 · 빨강=수급약함/간격큼. OR=총사겠음÷총팔겠음. 매수칸과 시각이 다름.">매도호가<br><span style="font-size:9px;font-weight:400;opacity:.7">녹OK · 노랑참고 · 빨강나쁨</span></th><th>매도사유</th>
</tr></thead>
<tbody id="act_tbody"></tbody>
</table>
@@ -536,7 +536,7 @@
<option value="ls">LS (ls_candidates)</option>
</select>
<label class="mb-0 ms-2">캔들</label>
<select class="form-select form-select-sm" id="bt_candle_source" style="width:70px" title="기본=실매 LIVE_TICK_PROVIDER 우선 병합">
<select class="form-select form-select-sm" id="bt_candle_source" style="width:70px" title="기본=실매 메인 WS, 구멍=키움 REST">
<option value="" title="실매 LIVE_TICK_PROVIDER 순서 (kiwoom→kis→rest)">기본</option><option value="kis">KIS</option><option value="kiwoom">키움</option>
</select>
<label class="mb-0 ms-1">시세(틱)</label>
@@ -787,7 +787,7 @@
<thead><tr>
<th>종목</th><th>매수시각</th><th>매도시각</th>
<th>매수가</th><th>매도가</th><th>수량</th>
<th>손익(원)</th><th>수익률%</th><th>누적손익</th><th>누적%</th><th>보유(분)</th><th title="매수 시점 호가 (M:L3잔량비 W:전체잔량비 OR)">매수호가</th><th title="매도 시점 호가 (M:L3잔량비 W:전체잔량비 OR)">매도호가</th><th>매도사유</th><th>진입RSI</th>
<th>손익(원)</th><th>수익률%</th><th>누적손익</th><th>누적%</th><th>보유(분)</th><th title="【살 때】 녹=괜찮음 · 노랑=숫자만/기록없음 · 빨강=간격큼/살힘약함/팔대기많음. 가격간격=낮을수록 좋음, 살힘=높을수록 좋음(1≈균형).">매수호가<br><span style="font-size:9px;font-weight:400;opacity:.7">녹OK · 노랑참고 · 빨강나쁨</span></th><th title="【팔 때】 녹=수급OK · 노랑=숫자만 · 빨강=수급약함/간격큼. OR=총사겠음÷총팔겠음. 매수칸과 시각이 다름.">매도호가<br><span style="font-size:9px;font-weight:400;opacity:.7">녹OK · 노랑참고 · 빨강나쁨</span></th><th>매도사유</th><th>진입RSI</th>
</tr></thead>
<tbody id="bt_tbody"></tbody>
</table>
@@ -873,7 +873,7 @@
<option value="ls">LS (ls_candidates)</option>
</select>
<label class="mb-0 ms-2">캔들</label>
<select class="form-select form-select-sm" id="tl_candle_source" style="width:70px" title="기본=실매 LIVE_TICK_PROVIDER 우선 병합">
<select class="form-select form-select-sm" id="tl_candle_source" style="width:70px" title="기본=실매 메인 WS, 구멍=키움 REST">
<option value="" title="실매 LIVE_TICK_PROVIDER 순서 (kiwoom→kis→rest)">기본</option><option value="kis">KIS</option><option value="kiwoom">키움</option>
</select>
<label class="mb-0 ms-1">시세(틱)</label>
@@ -1377,7 +1377,7 @@
<th>종목</th><th>매수시각</th><th>매도시각</th>
<th>매수가</th><th>매도가</th><th>수량</th>
<th>손익(원)</th><th>수익률%</th><th>누적손익</th><th>누적%</th>
<th>보유(분)</th><th>체결디버그</th><th title="매수 시점 호가 (M:L3잔량비 W:전체잔량비 OR)">매수호가</th><th title="매도 시점 호가 (M:L3잔량비 W:전체잔량비 OR)">매도호가</th><th>매도사유</th>
<th>보유(분)</th><th>체결디버그</th><th title="【살 때】 녹=괜찮음 · 노랑=숫자만/기록없음 · 빨강=간격큼/살힘약함/팔대기많음. 가격간격=낮을수록 좋음, 살힘=높을수록 좋음(1≈균형).">매수호가<br><span style="font-size:9px;font-weight:400;opacity:.7">녹OK · 노랑참고 · 빨강나쁨</span></th><th title="【팔 때】 녹=수급OK · 노랑=숫자만 · 빨강=수급약함/간격큼. OR=총사겠음÷총팔겠음. 매수칸과 시각이 다름.">매도호가<br><span style="font-size:9px;font-weight:400;opacity:.7">녹OK · 노랑참고 · 빨강나쁨</span></th><th>매도사유</th>
</tr></thead>
<tbody id="tl_tbody"></tbody>
</table>
@@ -1806,7 +1806,7 @@
<option value="ls">LS (ls_candidates)</option>
</select>
<label class="mb-0 ms-2">캔들</label>
<select class="form-select form-select-sm" id="bo_candle_source" style="width:70px" title="기본=실매 LIVE_TICK_PROVIDER 우선 병합">
<select class="form-select form-select-sm" id="bo_candle_source" style="width:70px" title="기본=실매 메인 WS, 구멍=키움 REST">
<option value="" title="실매 LIVE_TICK_PROVIDER 순서 (kiwoom→kis→rest)">기본</option><option value="kis">KIS</option><option value="kiwoom">키움</option>
</select>
<label class="mb-0 ms-1">시세(틱)</label>
@@ -1950,7 +1950,7 @@
<th>종목</th><th>매수시각</th><th>매도시각</th>
<th>매수가</th><th>매도가</th><th>수량</th>
<th>손익(원)</th><th>수익률%</th><th>누적손익</th><th>누적%</th>
<th>보유(분)</th><th>체결디버그</th><th title="매수 시점 호가 (M:L3잔량비 W:전체잔량비 OR)">매수호가</th><th title="매도 시점 호가 (M:L3잔량비 W:전체잔량비 OR)">매도호가</th><th>매도사유</th>
<th>보유(분)</th><th>체결디버그</th><th title="【살 때】 녹=괜찮음 · 노랑=숫자만/기록없음 · 빨강=간격큼/살힘약함/팔대기많음. 가격간격=낮을수록 좋음, 살힘=높을수록 좋음(1≈균형).">매수호가<br><span style="font-size:9px;font-weight:400;opacity:.7">녹OK · 노랑참고 · 빨강나쁨</span></th><th title="【팔 때】 녹=수급OK · 노랑=숫자만 · 빨강=수급약함/간격큼. OR=총사겠음÷총팔겠음. 매수칸과 시각이 다름.">매도호가<br><span style="font-size:9px;font-weight:400;opacity:.7">녹OK · 노랑참고 · 빨강나쁨</span></th><th>매도사유</th>
</tr></thead>
<tbody id="bo_tbody"></tbody>
</table>
@@ -2230,7 +2230,7 @@
<option value="ls">LS (ls_candidates)</option>
</select>
<label class="mb-0 ms-2">캔들</label>
<select class="form-select form-select-sm" id="mom_candle_source" style="width:70px" title="기본=실매 LIVE_TICK_PROVIDER 우선 병합">
<select class="form-select form-select-sm" id="mom_candle_source" style="width:70px" title="기본=실매 메인 WS, 구멍=키움 REST">
<option value="" title="실매 LIVE_TICK_PROVIDER 순서 (kiwoom→kis→rest)">기본</option><option value="kis">KIS</option><option value="kiwoom">키움</option>
</select>
<label class="mb-0 ms-1">시세(틱)</label>
@@ -2649,7 +2649,7 @@
<th>종목</th><th>매수시각</th><th>매도시각</th>
<th>매수가</th><th>매도가</th><th>수량</th>
<th>손익(원)</th><th>수익률%</th><th>누적손익</th><th>누적%</th>
<th>보유(분)</th><th>체결디버그</th><th title="매수 시점 호가 (M:L3잔량비 W:전체잔량비 OR)">매수호가</th><th title="매도 시점 호가 (M:L3잔량비 W:전체잔량비 OR)">매도호가</th><th>매도사유</th>
<th>보유(분)</th><th>체결디버그</th><th title="【살 때】 녹=괜찮음 · 노랑=숫자만/기록없음 · 빨강=간격큼/살힘약함/팔대기많음. 가격간격=낮을수록 좋음, 살힘=높을수록 좋음(1≈균형).">매수호가<br><span style="font-size:9px;font-weight:400;opacity:.7">녹OK · 노랑참고 · 빨강나쁨</span></th><th title="【팔 때】 녹=수급OK · 노랑=숫자만 · 빨강=수급약함/간격큼. OR=총사겠음÷총팔겠음. 매수칸과 시각이 다름.">매도호가<br><span style="font-size:9px;font-weight:400;opacity:.7">녹OK · 노랑참고 · 빨강나쁨</span></th><th>매도사유</th>
</tr></thead>
<tbody id="mom_tbody"></tbody>
</table>
@@ -3165,7 +3165,7 @@
<th>종목</th><th>매수시각</th><th>매도시각</th>
<th>매수가</th><th>매도가</th><th>수량</th>
<th>손익</th><th>수익률%</th><th>누적손익</th><th>누적%</th>
<th>보유(분)</th><th>체결디버그</th><th title="매수 시점 호가 (M:L3잔량비 W:전체잔량비 OR)">매수호가</th><th title="매도 시점 호가 (M:L3잔량비 W:전체잔량비 OR)">매도호가</th><th>매도사유</th>
<th>보유(분)</th><th>체결디버그</th><th title="【살 때】 녹=괜찮음 · 노랑=숫자만/기록없음 · 빨강=간격큼/살힘약함/팔대기많음. 가격간격=낮을수록 좋음, 살힘=높을수록 좋음(1≈균형).">매수호가<br><span style="font-size:9px;font-weight:400;opacity:.7">녹OK · 노랑참고 · 빨강나쁨</span></th><th title="【팔 때】 녹=수급OK · 노랑=숫자만 · 빨강=수급약함/간격큼. OR=총사겠음÷총팔겠음. 매수칸과 시각이 다름.">매도호가<br><span style="font-size:9px;font-weight:400;opacity:.7">녹OK · 노랑참고 · 빨강나쁨</span></th><th>매도사유</th>
</tr></thead>
<tbody id="usmom_tbody"></tbody>
</table>
@@ -3584,9 +3584,16 @@
<div id="tab-updow" style="display:none">
<!-- ═══ 영구구독 관리 (국내 WS H0STCNT0 + 해외 WS HDFSCNT0) ═══ -->
<div class="card p-3 mb-3">
<div class="d-flex justify-content-between align-items-center mb-2">
<h6 class="mb-0">📡 영구구독 관리 <small class="text-muted">(KR=국내 WS · US=해외 WS · 저장봉=1분→롤업)</small></h6>
<button class="btn btn-sm btn-outline-secondary" type="button" onclick="permLoad()">새로고침</button>
<div class="d-flex justify-content-between align-items-center mb-2 flex-wrap gap-2">
<h6 class="mb-0">📡 영구구독 관리 <small class="text-muted">(KR=LS WS · US=해외 WS · 저장봉=1분→롤업)</small></h6>
<div class="d-flex align-items-center gap-2">
<div class="form-check form-switch mb-0">
<input class="form-check-input" type="checkbox" id="perm_master_en" checked onchange="permSaveMaster()">
<label class="form-check-label" for="perm_master_en">구독 마스터</label>
</div>
<button class="btn btn-sm btn-outline-primary" type="button" onclick="permFillCandles('')">KR 확정봉 가져오기</button>
<button class="btn btn-sm btn-outline-secondary" type="button" onclick="permLoad()">새로고침</button>
</div>
</div>
<div class="row g-2 align-items-end flex-wrap mb-2">
<div class="col-auto">
@@ -3629,7 +3636,7 @@
<tbody id="perm_tbody"><tr><td colspan="9" class="text-muted">로딩…</td></tr></tbody>
</table>
</div>
<small class="text-muted">저장봉은 전부 <b>1분</b>(상위 15/60분은 롤업). TF 입력 없음. 현재가=WS 1분봉 DB(틱전수스캔·외부환율 HTTP 없음). US는 <b>$ + 원</b> 병기(표시용 환율). 탭 열면 자동 새로고침.</small>
<small class="text-muted">저장봉은 전부 <b>1분</b>(상위 15/60분은 롤업). TF 입력 없음. KR 현재가=<b>ls_ws_candles</b>. 「확정봉 가져오기」=키움 ka10080 → <b>ls_ws_candles 구멍만</b>(ws_candles 에 넣지 않음). 마스터 OFF=행 유지·구독만 해제(봇 재시작). US는 <b>$ + 원</b> 병기. 탭 열면 자동 새로고침.</small>
</div>
</div><!-- tab-updow end -->
@@ -3727,6 +3734,12 @@
<input class="form-check-input opt-strat-cb" type="checkbox" value="us_momentum"> 해외모멘텀(전역)
</label>
<label class="form-check form-check-inline mb-0"><input class="form-check-input opt-strat-cb" type="checkbox" value="tail"> 꼬리</label>
<label class="form-check form-check-inline mb-0 ms-1" title="꼬리 TPE만. 한 스터디=한 모드. 둘 다 켜면 align 다음 limit_atr 순차 2회">
<input class="form-check-input" type="checkbox" id="opt_tail_em_align" checked> align
</label>
<label class="form-check form-check-inline mb-0" title="지정가 ATR. 틱재생 ON 권장. 엔진 실매 기본값과 동일 계열">
<input class="form-check-input" type="checkbox" id="opt_tail_em_limit"> limit_atr
</label>
<label class="form-check form-check-inline mb-0"><input class="form-check-input opt-strat-cb" type="checkbox" value="breakout"> 돌파</label>
<label class="form-check form-check-inline mb-0"><input class="form-check-input opt-strat-cb" type="checkbox" value="scalp"> 스캘핑</label>
<button type="button" class="btn btn-sm btn-outline-secondary py-0" onclick="optunaPickKr4()">국내4</button>
@@ -3758,7 +3771,7 @@
</div>
<div class="col-auto">
<label class="form-label param-row">캔들소스</label>
<select class="form-select form-select-sm" id="opt_candle_source" style="width:80px" title="기본=실매 LIVE_TICK_PROVIDER 우선 병합">
<select class="form-select form-select-sm" id="opt_candle_source" style="width:80px" title="기본=실매 메인 WS, 구멍=키움 REST">
<option value="" selected title="실매 LIVE_TICK_PROVIDER 순서 (kiwoom→kis→rest)">기본</option>
<option value="kis">KIS</option>
<option value="kiwoom">키움</option>
@@ -3786,7 +3799,7 @@
<button class="btn btn-sm btn-outline-secondary" onclick="optunaRefreshJobs()">새로고침</button>
</div>
</div>
<small class="text-muted d-block mt-2">탐색 게이트 WR/PF=0 · 사후=results_gated · 안정=results_stable · DB 자동적용 안 함 · 2개 이상=순차(병렬 아님) · 이력소스=저장 후보 테이블</small>
<small class="text-muted d-block mt-2">탐색 게이트 WR/PF=0 · 사후=results_gated · 안정=results_stable · DB 자동적용 안 함 · 2개 이상=순차(병렬 아님) · 이력소스=저장 후보 테이블 · 꼬리 진입 align/limit_atr 둘 다=스터디 2개 순차(한 TPE에 섞지 않음)</small>
</div>
<div class="card p-3 mb-3" id="opt_status_card">
@@ -3812,13 +3825,16 @@
<button class="btn btn-sm btn-success" id="opt_btn_apply_gated" onclick="optunaApply('gated',1)">
✅ 사후합격 1위 DB 적용
</button>
<span id="opt_overfit_badge_gated" class="small ms-1" title="과적합%=이 숫자만 믿으면 내일 틀릴 수 있는 정도(추정). AI 아님."></span>
<button class="btn btn-sm btn-outline-info" id="opt_btn_apply_stable" onclick="optunaApply('stable',1)">
🛡️ 안정 1위 DB 적용
</button>
<span id="opt_overfit_badge_stable" class="small ms-1" title="과적합%=이 숫자만 믿으면 내일 틀릴 수 있는 정도(추정). AI 아님."></span>
<button class="btn btn-sm btn-outline-success" id="opt_btn_apply_mode" onclick="optunaApply('mode',1)">
mode_combo DB 적용
</button>
<small class="text-muted ms-2">완료 후에만 · TIME_* 미변경 · confirm 필수</small>
<span id="opt_overfit_badge_mode" class="small ms-1" title="과적합%=이 숫자만 믿으면 내일 틀릴 수 있는 정도(추정). AI 아님."></span>
<small class="text-muted ms-2">완료 후에만 · TIME_* 미변경 · 위 버튼=타점만 · 트레일/호가는 아래 표 · confirm 필수</small>
</div>
</div>
@@ -3840,32 +3856,51 @@
</div>
<div id="opt_vs_best" class="small text-muted"></div>
<div id="opt_stable_gates" class="small text-muted mt-1"></div>
<div id="opt_daily_trail_rec" class="mt-2 p-2 small" style="background:rgba(56,139,253,0.08);border:1px solid var(--border);border-radius:6px">
<div class="text-muted mb-1">다단트레일 추천 <span class="text-muted">(탐색 축 아님 · DB 적용 시에만 반영)</span></div>
<div id="opt_daily_trail_rec_body">완료 후 표시</div>
</div>
<div id="opt_postprocess_rec" class="mt-2 p-2 small" style="background:rgba(63,185,80,0.06);border:1px solid var(--border);border-radius:6px">
<div class="text-muted mb-1">후처리 추천 표
<span class="text-muted">(호가 진입+익절 · 휩쏘 · 트레일 · <b>STOP_OB 합의 아직 없음</b>)</span>
<div id="opt_overfit_box" class="mt-2 p-2 small" style="background:rgba(248,81,73,0.06);border:1px solid var(--border);border-radius:6px">
<div class="d-flex flex-wrap justify-content-between gap-2 mb-1">
<div class="text-muted">과적합·적용 가능도 <span class="text-muted">(휴리스틱 · 교차검증 아님)</span></div>
<div id="opt_overfit_score" class="fw-semibold">완료 후 표시</div>
</div>
<div class="table-responsive mb-2">
<table class="table table-sm table-hover mb-0" style="font-size:12px">
<thead>
<tr>
<th>요인</th><th class="text-end">가점</th><th>설명</th>
</tr>
</thead>
<tbody id="opt_overfit_factors_tbody">
<tr><td colspan="3" class="text-muted">완료 후 표시</td></tr>
</tbody>
</table>
</div>
<div class="text-muted mb-1">임계값 분포 <span id="opt_thresh_pool" class="text-muted"></span></div>
<div class="table-responsive">
<table class="table table-sm table-hover mb-0" style="font-size:12px">
<thead>
<tr>
<th>구분</th><th>상태</th><th>핵심 수치</th>
<th class="text-end">모수/통계</th><th>비고</th>
<th>파라미터</th>
<th class="text-end">median</th>
<th class="text-end">p25</th>
<th class="text-end">p75</th>
<th>mode</th>
<th class="text-end">mode%</th>
</tr>
</thead>
<tbody id="opt_postprocess_tbody">
<tr><td colspan="5" class="text-muted">완료 후 표시</td></tr>
<tbody id="opt_thresh_dist_tbody">
<tr><td colspan="6" class="text-muted">완료 후 표시</td></tr>
</tbody>
</table>
</div>
<div id="opt_overfit_note" class="text-muted mt-1" style="font-size:11px"></div>
</div>
<div id="opt_daily_trail_rec" class="mt-2 p-2 small" style="background:rgba(56,139,253,0.08);border:1px solid var(--border);border-radius:6px">
<div class="text-muted mb-1">다단트레일 추천 <span class="text-muted">(탐색 축 아님 · DB 적용 시에만 반영)</span></div>
<div id="opt_daily_trail_rec_body">완료 후 표시</div>
</div>
</div>
<div class="card p-3 mb-3">
<h6>사후합격 Top5 <small class="text-muted">results_gated</small></h6>
<h6>사후합격 Top5 <small class="text-muted">results_gated · 「상세」=아래 후처리 표</small></h6>
<div class="table-responsive">
<table class="table table-sm table-hover mb-0" style="font-size:12px">
<thead>
@@ -3879,6 +3914,20 @@
</tbody>
</table>
</div>
<div id="opt_postprocess_rec" class="mt-3 p-2 small" style="background:rgba(63,185,80,0.06);border:1px solid var(--border);border-radius:6px">
<div class="text-muted mb-1">후처리 비교표
<span class="text-muted">(Top5 「상세」로 순위 전환 · 열까지 적용=뒤쪽 축은 OFF · 숫자는 유지 · live 참고만)</span>
</div>
<div class="mb-2">
<button class="btn btn-sm btn-outline-secondary py-0" id="opt_btn_pp_rerun" onclick="optunaRerunPostprocess()">이 잡 후처리 재실행</button>
<button class="btn btn-sm btn-outline-secondary py-0 ms-1" onclick="optunaSelectPostprocess('mode',1)">mode 상세</button>
<span id="opt_pp_rerun_status" class="text-muted ms-1">구 JSON은 재실행해야 호가/휩쏘 숫자가 채워집니다.</span>
</div>
<div id="opt_postprocess_consensus" class="mb-1">합의: 완료 후 표시</div>
<div id="opt_postprocess_cards">
<div class="text-muted">Top5에서 「상세」를 누르면 이 표가 바뀝니다.</div>
</div>
</div>
</div>
<div class="card p-3 mb-3">