feat: 새로운 안전 규칙 및 최적화 적용을 통한 트레이딩 시스템 개선
변경 사항 (Changes): 구문 오류(Syntax error) 및 토큰 낭비를 방지하기 위해 에이전트 쉘(Agent shell)과 파이썬 코드 스니펫에 다수의 신규 안전 규칙(Safety rules)을 추가함. 스키마 검증 및 적절한 SQL 포맷팅을 보장하기 위해 임시(Ad-hoc) 데이터베이스 쿼리 작성 가이드라인을 도입함. 코드 수정 후 UI 기능이 정상 작동하는지 확인하기 위해, 백테스트 웹 서비스 재시작 및 브라우저 검증에 대한 새로운 규칙을 구현함. 시스템 전반의 무결성(Integrity)을 유지하기 위해 실전 매매(Live trading), 웹 백테스팅, 파라미터 탐색(Parameter searches) 간의 일관성 검사(Consistency checks) 체계를 확립함. 기대 효과 (Impact): 이러한 개선 사항들은 트레이딩 시스템의 견고성(Robustness)과 신뢰성을 향상시키며, 에러 발생을 최소화하고 다양한 시스템 컴포넌트 간의 원활한 상호작용을 보장함.
This commit is contained in:
45
.cursor/rules/agent-shell-python-safety.mdc
Normal file
45
.cursor/rules/agent-shell-python-safety.mdc
Normal file
@@ -0,0 +1,45 @@
|
||||
---
|
||||
description: 에이전트 셸·Python 원라이너 — 문법 오류 코드 금지로 토큰/재실행 낭비 방지
|
||||
alwaysApply: true
|
||||
---
|
||||
|
||||
# 에이전트 셸 / Python 스니펫 안전 (토큰 절약)
|
||||
|
||||
대화에서 실제로 낭비된 패턴: **실행 전에 문법이 틀린 Python을 heredoc으로 돌림**
|
||||
(예: `from X import Y if False else None` → `SyntaxError` → 재작성으로 턴·토큰 낭비).
|
||||
|
||||
## 1. 실행 전 문법 유효성 (필수)
|
||||
|
||||
- `python - <<'PY'` / `-c` / 임시 `.py` 를 **돌리기 전에** 문법이 맞는지 스스로 확인.
|
||||
- 확신이 없으면 파일로 쓴 뒤 `python -m py_compile path.py` **1회**만 하고 실행.
|
||||
- `SyntaxError` / `IndentationError` 나면 **원인 고친 뒤 1회만** 재실행. 같은 스니펫을 살짝만 바꿔 반복 금지.
|
||||
|
||||
## 2. 금지 패턴 (자주 나는 가짜 문법)
|
||||
|
||||
- `from module import name if cond else None` — **문법 불가**.
|
||||
→ `import module as m` 후 `getattr(m, "name", None)` 또는 `try/except ImportError`.
|
||||
- `from X import a, b if c` / 조건부 import를 `from` 한 줄에 섞기.
|
||||
- 존재하지 않는 심볼을 **추측 import** (`get_scalp_grids` 등).
|
||||
→ 먼저 `hasattr` / `dir` / Grep으로 실명 확인 후 import.
|
||||
- heredoc 안에서 이전에 실패한 코드를 **거의 그대로** 다시 붙여 넣기.
|
||||
|
||||
## 3. 그리드·헬퍼 조회 스니펫 최소형
|
||||
|
||||
축 개수 세기 등은 아래처럼 **검증된 형태만** 사용 (조건부 from 금지):
|
||||
|
||||
```python
|
||||
from kis_trader.backtest.param_search_breakout import _breakout_grids
|
||||
import kis_trader.backtest.param_search_scalping as sc
|
||||
|
||||
bg = _breakout_grids()
|
||||
print({m: len(a) for m, a in bg.items()})
|
||||
fn = getattr(sc, "_scalp_grids", None)
|
||||
print({m: len(a) for m, a in fn().items()} if callable(fn) else "no _scalp_grids")
|
||||
```
|
||||
|
||||
시그니처를 모르면 `inspect.signature(fn)` **먼저** — `_tail_grids(mode)` 처럼 인자가 필요한데 `()`로 호출하지 말 것.
|
||||
|
||||
## 4. 토큰 절약 원칙
|
||||
|
||||
- “한 번에 여러 전략 import + 조건부 트릭”보다 **짧은 확정 코드 1회**.
|
||||
- 실패 로그를 사용자에게 길게 반복 붙여 넣지 말 것. 고치고 결과만 보고.
|
||||
46
.cursor/rules/backtest-web-restart.mdc
Normal file
46
.cursor/rules/backtest-web-restart.mdc
Normal file
@@ -0,0 +1,46 @@
|
||||
---
|
||||
description: 백테 웹 수정 후 systemctl 재시작 + 브라우저로 열어 클릭 검증까지 완료
|
||||
alwaysApply: true
|
||||
---
|
||||
|
||||
# 백테 웹 재시작 + 브라우저 검증 (필수)
|
||||
|
||||
`backtest_web.py` · `templates/backtest.html` · `static/js/backtest.js` · `kis_trader/web/**` 등 **웹 UI/API에 반영되는 코드**를 수정한 뒤에는:
|
||||
|
||||
1. 사용자에게 “재시작/새로고침하세요”만 말하지 말고 **직접 재시작**
|
||||
2. **페이지를 띄워 관련 UI를 눌러보는 검증까지** 끝낸 뒤에야 “완료”로 보고
|
||||
|
||||
`curl 200` / `systemctl active` 만으로는 검증 완료가 **아님**. 콘솔 `ReferenceError`·버튼 미동작은 브라우저 클릭 없이는 놓친다.
|
||||
|
||||
## 1) 재시작
|
||||
|
||||
```bash
|
||||
sudo systemctl restart kis_backtest_web.service
|
||||
sleep 2
|
||||
systemctl is-active kis_backtest_web.service
|
||||
curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:5050/
|
||||
```
|
||||
|
||||
- 유닛: `kis_backtest_web.service` (포트 **5050**)
|
||||
- 실패 시: `journalctl -u kis_backtest_web.service -n 40 --no-pager`
|
||||
|
||||
## 2) 브라우저 검증 (수정 범위만큼)
|
||||
|
||||
브라우저 도구로 `http://127.0.0.1:5050/` (또는 LAN `http://192.168.0.149:5050/`) 을 연다.
|
||||
|
||||
- 강력 새로고침에 해당하는 방식으로 최신 JS/HTML 로드
|
||||
- **수정한 탭·버튼·날짜 인풋·정렬·거래내역**을 실제로 클릭/입력
|
||||
- DevTools 콘솔에 `Uncaught` / `ReferenceError` / 빨간 네트워크 실패가 **없어야** 함
|
||||
- 스냅샷으로 화면 상태 확인 후, 잔여 오류가 있으면 고치고 재검증
|
||||
|
||||
최소 산출물(보고에 포함):
|
||||
|
||||
- 재시작 결과 (`active` + HTTP 코드)
|
||||
- 연 URL + 누른 탭/버튼
|
||||
- 콘솔 오류 유무 (없으면 “콘솔 오류 없음”)
|
||||
|
||||
## 언제
|
||||
|
||||
- Python API/서버 변경 → 재시작 **필수** + 브라우저 검증
|
||||
- `static/` · `templates/` 만 변경 → 재시작(또는 캐시 무효) + **브라우저 검증 필수**
|
||||
- 실매 봇(`kis_trader_main` 등)은 웹과 무관하면 재시작하지 말 것
|
||||
50
.cursor/rules/db-adhoc-query-safety.mdc
Normal file
50
.cursor/rules/db-adhoc-query-safety.mdc
Normal file
@@ -0,0 +1,50 @@
|
||||
---
|
||||
description: TradeDB/MariaDB 임시 조회 시 스키마 확인·PyMySQL % 이스케이프 필수 (실패 재시도 금지)
|
||||
alwaysApply: true
|
||||
---
|
||||
|
||||
# DB 임시 조회(adhoc) 안전 규칙
|
||||
|
||||
TradeDB/`database.py`로 SQL을 날릴 때 **추측 쿼리 금지**. 실패하면 같은 가정을 반복하지 말 것(토큰 낭비).
|
||||
|
||||
## 1. 쿼리 전에 스키마 확인 (필수)
|
||||
|
||||
모르는 테이블/컬럼이면 **먼저** `SHOW COLUMNS FROM <table>` 또는 `DESCRIBE <table>`.
|
||||
|
||||
대표 함정:
|
||||
|
||||
| 테이블 | 주의 |
|
||||
|--------|------|
|
||||
| `target_candidates` | **전략 컬럼 없음** (code/name/score/price/scan_time/updated_at + market/sector/theme). `strategy_id` SELECT 금지 |
|
||||
| `target_candidates_history` | 컬럼은 `SHOW COLUMNS`로 확인 후 사용. CREATE 기본 DDL과 실제 DB가 다를 수 있음 |
|
||||
| 전략별 후보 | history의 `strategy_id` 또는 별도 테이블/코드 경로를 문서·스키마로 확인 |
|
||||
|
||||
## 2. PyMySQL `%` 포맷 충돌 (필수)
|
||||
|
||||
`TradeDB.conn.execute()`는 pymysql이라 SQL 문자열의 `%`가 포맷으로 해석된다.
|
||||
|
||||
- ❌ `LIKE '20260712%'` / `LIKE '%BREAK%'` (단독 문자열에 `%`)
|
||||
- ✅ 바인딩: `LIKE %s` + params `('20260712%',)`
|
||||
- ✅ 또는 `%%` 이스케이프: `LIKE '20260712%%'`
|
||||
|
||||
`not enough arguments for format string` = 이 문제. 스키마 문제가 아님.
|
||||
|
||||
## 3. 실패 시 재시도 규칙
|
||||
|
||||
1. 에러 읽기 → 원인 분류(포맷 vs 컬럼없음 vs 테이블없음)
|
||||
2. **스키마/바인딩 고친 뒤 1회만** 재실행
|
||||
3. 같은 실패를 다른 날짜·다른 strategy 문자열로 반복 금지
|
||||
4. 불확실하면 `database.py`의 CREATE/migrate/`get_*` 헬퍼를 읽고 그걸 쓰거나, 헬퍼에 없는 조회면 스키마 확인 후 작성
|
||||
|
||||
## 4. 최소 템플릿
|
||||
|
||||
```python
|
||||
from database import TradeDB
|
||||
db = TradeDB()
|
||||
cols = [r["Field"] for r in db.conn.execute("SHOW COLUMNS FROM target_candidates_history").fetchall()]
|
||||
# cols 확인 후 SELECT. LIKE는 반드시 %s 바인딩
|
||||
rows = db.conn.execute(
|
||||
"SELECT slot_key, COUNT(*) n FROM target_candidates_history WHERE slot_key LIKE %s GROUP BY slot_key",
|
||||
("20260712%",),
|
||||
).fetchall()
|
||||
```
|
||||
65
.cursor/rules/hts-condition-grids.mdc
Normal file
65
.cursor/rules/hts-condition-grids.mdc
Normal file
@@ -0,0 +1,65 @@
|
||||
---
|
||||
description: HTS=SCAN 유니버스만 — TRIGGER/그리드는 HTS와 동일 조건 중복 필터 금지
|
||||
alwaysApply: true
|
||||
---
|
||||
|
||||
# HTS 조건식 vs 코드·그리드 (정정)
|
||||
|
||||
**HTS에 그리드/TRIGGER를 “맞출” 필요 없다.**
|
||||
조건검색이 이미 후보를 걸렀으므로, 코드·Optuna에서 **같은 축을 또 거르지 않는다.**
|
||||
|
||||
## 역할 분리
|
||||
|
||||
| 단계 | 역할 |
|
||||
|------|------|
|
||||
| **HTS (SCAN)** | 유니버스·후보 풀. 일봉/조건식 숫자로 1차 선별 |
|
||||
| **코드 TRIGGER** | HTS와 **다른** 타점·청산·호가·리스크 (중복 재필터 금지) |
|
||||
| **Optuna 그리드** | TRIGGER/청산/포트 축 탐색. **HTS 밴드 재현이 목적 아님** |
|
||||
|
||||
## 하지 말 것
|
||||
|
||||
- HTS 등락 3~10% / vol 150% / min_price 2000 등을 **그리드에 넣어야 한다**고 강제하지 말 것
|
||||
- “HTS와 안 맞는다”며 fast 그리드를 HTS 숫자로 채우지 말 것
|
||||
- SCAN에서 이미 통과한 종목에 TRIGGER에서 **동일 의미의 일봉 조건**을 다시 적용하지 말 것 (의도적 이중필터가 아니면)
|
||||
|
||||
## 해도 되는 것
|
||||
|
||||
- HTS 원본은 **문서·운영 참고**로만 유지 (아래 표)
|
||||
- TRIGGER는 분봉·호가·ATR·어깨·트레일·RSI 등 **타점/청산** 축
|
||||
- 실매 DB ↔ 웹백테 ↔ Optuna **동일 엔진** 정합(항목 15)은 그대로. 그건 HTS 복제가 아님
|
||||
|
||||
## `*_SKIP_HTS_SCAN_DUPES` — 기본 false 유지
|
||||
|
||||
| 키 | 운영 기본 |
|
||||
|----|-----------|
|
||||
| `TAIL_SKIP_HTS_SCAN_DUPES` | **false** |
|
||||
| `MOMENTUM_SKIP_HTS_SCAN_DUPES` | **false** |
|
||||
| `BREAKOUT_SKIP_HTS_SCAN_DUPES` | **false** / `0` |
|
||||
| `SCALP_SKIP_HTS_SCAN_DUPES` | **false** / `0` |
|
||||
|
||||
- **false**: TRIGGER에서 HTS와 겹칠 수 있는 축도 검사 (현재 운영값).
|
||||
- **true**: HTS SCAN 중복 필터 스킵.
|
||||
- 사용자가 **명시적으로** true/변경을 말하지 않으면 **false 유지**. 임의로 true로 바꾸거나 “철학상 true가 맞다”며 DB/기본값을 고치지 말 것.
|
||||
- Optuna 그리드에 `[True, False]` 스윕이 있어도, **실매·웹 기본값/DB 적용**은 사용자 지시 없이 false 유지.
|
||||
|
||||
## 주말 종목수
|
||||
|
||||
주말 HTS 후보 증가 ≠ 시장 호전 (이탈 없음). 그리드 이슈와 무관.
|
||||
|
||||
---
|
||||
|
||||
## 참고: 현재 HTS 원본 (SCAN 전용, 그리드 강제 아님)
|
||||
|
||||
### 돌파
|
||||
- 종가 1000~200000 · 5봉평균 대비 ≥150% · 전일고가 상향돌파 · 등락 3~10%
|
||||
|
||||
### 꼬리 — (A∨G)∧B∧D∧E∧F
|
||||
- A [일] 시가→종가 -10~-0.5% · G [1분] 직전종가→종가 -10~-0.5%
|
||||
- B 체결강도 85~400% · D 3봉전 대비 150~2000% · E 종가 1000~200000
|
||||
- F [일] 저가→종가 1~8%
|
||||
|
||||
### 모멘텀
|
||||
- 전시가 상향돌파 · 종가 1000~200000 · ≥105% · 거래량증감 상위 350
|
||||
|
||||
### 스캘핑
|
||||
- 시가→저가 -8~-1.5% · 저가→종가 2~12% · 5분평균 대비 1분 ≥1.5배 · 1봉 연속증가
|
||||
61
.cursor/rules/live-backtest-optuna-parity.mdc
Normal file
61
.cursor/rules/live-backtest-optuna-parity.mdc
Normal file
@@ -0,0 +1,61 @@
|
||||
---
|
||||
description: 실매↔웹백테↔파람 정합 — 파람서치는 Optuna 기본, 수정 후 교차검증 체크리스트
|
||||
alwaysApply: true
|
||||
---
|
||||
|
||||
# 실매 · 웹백테 · 파람서치 정합 (Optuna 기본)
|
||||
|
||||
`.cursorrules` 5·7번을 **실행 절차**로 구체화한다.
|
||||
전략 로직/파라미터/공통 엔진을 고치면 “코드만 맞춤”으로 끝내지 말고 **실매 기준 → 웹백테 → Optuna** 순으로 검증한다.
|
||||
|
||||
## 0. 파람서치 기본 = Optuna
|
||||
|
||||
- 사용자가 Grid CLI를 **명시**하지 않으면 파람서치는 **`param_search_optuna.py`** 를 쓴다.
|
||||
- 이유: trial 진행률·study 재개·TPE 탐색이 Grid보다 섬세하고 운영에 맞음.
|
||||
- Grid (`tail_param_search.py` 등)는 Optuna가 없는 전략·사용자가 Grid를 지정한 경우·그리드 공간 점검용만.
|
||||
- Optuna 대상: `tail` | `momentum` | `breakout` | `scalp` (`--strategy`).
|
||||
|
||||
## 1. 수정 시 맞출 대상 (한 축이라도 빠지면 미완료)
|
||||
|
||||
| 축 | 무엇 |
|
||||
|----|------|
|
||||
| 실매 | `*_engine` / Strategy + DB env (`get_*_defaults_from_db`) |
|
||||
| 웹백테 | `backtest_web.py` API + 해당 탭 인풋 = 실매 키·기본값 |
|
||||
| 파람 | Optuna 그리드 ⊃ **실매 TRIGGER/청산 핵심값** (HTS SCAN 밴드 재현 목적 아님 — `hts-condition-grids.mdc`) |
|
||||
| 공통 | 가능하면 엔진/헬퍼 1경로 공유 (백테·Optuna가 실매와 다른 분기 금지) |
|
||||
|
||||
## 2. 검증 체크리스트 (보고 전)
|
||||
|
||||
1. **거래일**: start/end = 최근 장운영일 (`kr_trading_day`). 주말·휴장 날짜로 돌리지 말 것.
|
||||
2. **실매 DB 스냅샷**: 해당 전략 핵심 파라미터 확인.
|
||||
3. **그리드 ⊃ 실매값**: Optuna mode 축에 실매값이 없으면 그리드 먼저 고침 (또는 사용자 보고 후 중단).
|
||||
4. **웹백테 1회**: 동일 start/end·동일 파라미터로 탭 실행 → 거래수·PnL·승률 기록. (웹 수정 시 항목 14 브라우저 검증 포함)
|
||||
5. **Optuna (기본)**:
|
||||
```bash
|
||||
python3 -u kis_trader/backtest/param_search_optuna.py \
|
||||
--strategy <tail|momentum|breakout|scalp> --mode <fast|coarse|fine|…> \
|
||||
--start YYYY-MM-DD --end YYYY-MM-DD \
|
||||
--trials N --min_trades 1 --orderbook-filter off --no-progress \
|
||||
--study-name <전략>_<mode>_<TS>
|
||||
# --apply-best 없음 (기본)
|
||||
```
|
||||
- nohup + 로그 경로 안내. `for+sleep` 폴링 금지.
|
||||
- categorical 그리드 변경 시 **새 study-name** 필수.
|
||||
6. **교차 비교**: 동일 기간 **현재 DB 백테 PnL** vs **Optuna best 백테 PnL** (헬퍼 재사용: `scripts/append_tail_optuna_compare.py` 등).
|
||||
- 수치·건수가 어긋나면 “정합 OK” 금지 → 원인 분류(엔진/유니버스/틱재생/포트폴리오).
|
||||
7. **DB 적용**: 사용자 `--apply-best`/적용 지시 **없으면** 저장 금지. 1일 best는 과적합 경고.
|
||||
|
||||
## 3. 완료 보고 최소 산출물
|
||||
|
||||
- 전략·기간(거래일)·mode·study-name·로그/JSON 경로
|
||||
- 현재 DB 백테 요약 (trades / WR / PnL)
|
||||
- Optuna best 요약 + Δ(현재 대비)
|
||||
- 웹백테를 돌렸으면 그 수치 (또는 “웹 미해당”)
|
||||
- 적용 여부: **미적용** / 사용자 지시로 적용
|
||||
|
||||
## 4. 하지 말 것
|
||||
|
||||
- Grid를 기본 경로로 돌리기 (사용자 미지정 시)
|
||||
- 실매만 고치고 웹·Optuna 그리드/기본값 방치
|
||||
- Optuna best를 검증 없이 DB 반영
|
||||
- 주말 날짜·구 study·실매값 빠진 그리드로 trial 낭비
|
||||
41
.cursor/rules/optuna-backtest-token-savings.mdc
Normal file
41
.cursor/rules/optuna-backtest-token-savings.mdc
Normal file
@@ -0,0 +1,41 @@
|
||||
---
|
||||
description: Optuna/백테/장일 확인·그리드-실매정합·긴잡폴링 금지로 토큰·재실행 낭비 방지
|
||||
alwaysApply: true
|
||||
---
|
||||
|
||||
# 파람서치·백테 운영 (토큰/재실행 절약)
|
||||
|
||||
**파람서치 기본 경로 = Optuna** (`param_search_optuna.py`). 정합·검증 절차는 `.cursor/rules/live-backtest-optuna-parity.mdc`.
|
||||
|
||||
이 대화에서 실제로 낭비된 패턴을 반복하지 말 것.
|
||||
|
||||
## 1. 장일(거래일) 먼저
|
||||
|
||||
- `오늘`/`end=오늘`이 **주말·공휴일**이면 봉/틱 없음 → **최근 거래일**로 바꿔 한 번만 실행.
|
||||
- 달력 확인 없이 Optuna/백테를 돌리지 말 것. (예: 7/11 일요일이라 7/10으로 재실행한 낭비)
|
||||
|
||||
## 2. Optuna study / 그리드 변경
|
||||
|
||||
- categorical 그리드(축·값)를 바꾼 뒤 **같은 `--study-name` 재사용 금지**.
|
||||
- `CategoricalDistribution does not support dynamic value space` = study 충돌 → 즉시 **새 study-name**으로 1회만 재시작. 폴링하며 같은 실패를 반복하지 말 것.
|
||||
- 그리드 변경 후 기본 명령에 `--study-name <전략>_<mode>_wide_<TS>` 포함.
|
||||
|
||||
## 3. 그리드 ⊃ 실매 DB 기본값 (실행 전)
|
||||
|
||||
- Optuna/`--mode` 돌리기 전에 **현재 DB 실매 TRIGGER·청산 핵심 파라미터**가 해당 mode 그리드에 있는지 검사.
|
||||
- HTS SCAN 조건을 그리드에 넣으라고 강제하지 말 것 (이미 조건식이 거름 — `hts-condition-grids.mdc`).
|
||||
- 실매값이 그리드에 없으면 trial 전에 고치거나 보고. **빈 격자 trial 금지**.
|
||||
|
||||
## 4. DB 미적용 기본
|
||||
|
||||
- 사용자가 `--apply-best`/DB반영을 명시하지 않으면 **적용하지 말 것**.
|
||||
- 1일 Optuna best는 과적합 가능 → 적용 권고 전에 비교표만.
|
||||
|
||||
## 5. 긴 잡: 폴링 루프 금지
|
||||
|
||||
- Optuna/백테는 `nohup`+로그 경로만 안내. 에이전트 턴에서 `for + sleep`으로 수십 회 폴링하지 말 것.
|
||||
- 진행 확인은 로그 `tail` 1회 또는 완료 알림 후. 비교는 `scripts/append_tail_optuna_compare.py` 등 **기존 헬퍼 재사용** (인라인 비교 스크립트 재작성 금지).
|
||||
|
||||
## 6. 주말 HTS 종목수
|
||||
|
||||
- 주말 후보 증가 = 시장 호전으로 단정하지 말 것. 장외 이탈 없음/일봉 sticky가 기본 가설. DB 조회는 `db-adhoc-query-safety` 준수.
|
||||
Reference in New Issue
Block a user