Spaces:
Running
Running
back to stage
Browse files- confirm_sell_backtest.py +24 -15
confirm_sell_backtest.py
CHANGED
|
@@ -19,7 +19,9 @@ import sys, ssl
|
|
| 19 |
import pandas as pd
|
| 20 |
import numpy as np
|
| 21 |
import FinanceDataReader as fdr
|
| 22 |
-
from datetime import datetime, timedelta
|
|
|
|
|
|
|
| 23 |
|
| 24 |
ssl._create_default_https_context = ssl._create_unverified_context
|
| 25 |
if sys.platform == 'win32':
|
|
@@ -39,15 +41,10 @@ TICKERS = {
|
|
| 39 |
],
|
| 40 |
'KOSDAQ': [
|
| 41 |
# '247540', '086520', '196170', '028300', '348370',
|
| 42 |
-
# '058470', '068760', '263750', '035900',
|
| 43 |
-
# '277810',
|
| 44 |
-
'234690',
|
| 45 |
# '041510', '035760', '112040', '293490', '145020',
|
| 46 |
-
# '039030', '240810', '357780',
|
| 47 |
-
|
| 48 |
-
# '121600',
|
| 49 |
-
# '399720',
|
| 50 |
-
# '234340',
|
| 51 |
],
|
| 52 |
}
|
| 53 |
|
|
@@ -80,8 +77,12 @@ ANALYZE_TO = None # None=오늘
|
|
| 80 |
# 잘못 잡아 매도시점이 달라지는 버그가 생김 -> 그래서 DATA_START 는 고정.)
|
| 81 |
DATA_START = '2018-01-01' # 고정. 더 과거를 보려면 이 날짜만 앞당기면 됨.
|
| 82 |
|
| 83 |
-
|
| 84 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 85 |
|
| 86 |
|
| 87 |
# =============================================
|
|
@@ -103,8 +104,9 @@ def _trailing_peaks(stock, index, win):
|
|
| 103 |
return pk, ipk
|
| 104 |
|
| 105 |
|
| 106 |
-
def find_confirmed_sells(stock, index, dates, start_pos):
|
| 107 |
"""확정매도(2차) 찾기 — 단계별 누적 하락 + 하루 이격 급변 점프.
|
|
|
|
| 108 |
고점 = '최근 PEAK_WINDOW(252) 거래일 내 최고점' (트레일링).
|
| 109 |
단계: flagON(대기) -> 1차(확정) -> 2차flagON(대기) -> 2차매도(확정)
|
| 110 |
- 평소: 직전 단계보다 이격 MIN_DEEPEN(2.5%p)+ 더 깊으면 다음 단계
|
|
@@ -180,6 +182,13 @@ def find_confirmed_sells(stock, index, dates, start_pos):
|
|
| 180 |
sells.append({'i': t, 'price': st, 'div': div, 'date': dates[t]})
|
| 181 |
sold = True
|
| 182 |
prev_div = div
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 183 |
return sells, jumps
|
| 184 |
|
| 185 |
|
|
@@ -220,7 +229,7 @@ def protected(stock, i, price):
|
|
| 220 |
|
| 221 |
def load_one(ticker, market):
|
| 222 |
try:
|
| 223 |
-
sdf = fdr.DataReader(ticker, DATA_START,
|
| 224 |
except Exception:
|
| 225 |
return None
|
| 226 |
if not isinstance(sdf, pd.DataFrame) or 'Close' not in sdf.columns or len(sdf) == 0:
|
|
@@ -229,7 +238,7 @@ def load_one(ticker, market):
|
|
| 229 |
idf = None
|
| 230 |
for c in (idx_code, '^' + idx_code):
|
| 231 |
try:
|
| 232 |
-
t = fdr.DataReader(c, DATA_START,
|
| 233 |
if isinstance(t, pd.DataFrame) and 'Close' in t.columns and len(t) > 0:
|
| 234 |
idf = t; break
|
| 235 |
except Exception:
|
|
@@ -261,7 +270,7 @@ def pct(a, b):
|
|
| 261 |
|
| 262 |
def main():
|
| 263 |
print("=" * 88)
|
| 264 |
-
print(f"이격 재확인 백테스트 [lower-low] | {ANALYZE_FROM} ~ {
|
| 265 |
f"{sum(len(v) for v in TICKERS.values())}개")
|
| 266 |
print(f"규칙: 고점=최근{PEAK_WINDOW}일내최고 | 단계누적({MIN_DEEPEN*100:.1f}%p+) | 하루급변({DAILY_JUMP*100:.0f}%p)점프 | 1차~2차 22일내 | 회복시재시작")
|
| 267 |
print(f"채점: 관찰 {LOOK_AHEAD}일 | E율=240이탈(조기경보) | P율=매도가대비 {PROTECT_DROP*100:.0f}% 추가하락 회피")
|
|
|
|
| 19 |
import pandas as pd
|
| 20 |
import numpy as np
|
| 21 |
import FinanceDataReader as fdr
|
| 22 |
+
from datetime import datetime, timedelta, timezone
|
| 23 |
+
|
| 24 |
+
_KST = timezone(timedelta(hours=9))
|
| 25 |
|
| 26 |
ssl._create_default_https_context = ssl._create_unverified_context
|
| 27 |
if sys.platform == 'win32':
|
|
|
|
| 41 |
],
|
| 42 |
'KOSDAQ': [
|
| 43 |
# '247540', '086520', '196170', '028300', '348370',
|
| 44 |
+
# '058470', '068760', '263750', '035900', '277810',
|
|
|
|
|
|
|
| 45 |
# '041510', '035760', '112040', '293490', '145020',
|
| 46 |
+
# '039030', '240810', '357780', '403870', '121600',
|
| 47 |
+
'399720',
|
|
|
|
|
|
|
|
|
|
| 48 |
],
|
| 49 |
}
|
| 50 |
|
|
|
|
| 77 |
# 잘못 잡아 매도시점이 달라지는 버그가 생김 -> 그래서 DATA_START 는 고정.)
|
| 78 |
DATA_START = '2018-01-01' # 고정. 더 과거를 보려면 이 날짜만 앞당기면 됨.
|
| 79 |
|
| 80 |
+
|
| 81 |
+
def _end_date():
|
| 82 |
+
"""데이터 끝날짜. ANALYZE_TO=None이면 매번 '지금 KST 오늘'로 계산(앱 켜둬도 최신)."""
|
| 83 |
+
if ANALYZE_TO:
|
| 84 |
+
return ANALYZE_TO
|
| 85 |
+
return datetime.now(_KST).strftime('%Y-%m-%d')
|
| 86 |
|
| 87 |
|
| 88 |
# =============================================
|
|
|
|
| 104 |
return pk, ipk
|
| 105 |
|
| 106 |
|
| 107 |
+
def find_confirmed_sells(stock, index, dates, start_pos, return_state=False):
|
| 108 |
"""확정매도(2차) 찾기 — 단계별 누적 하락 + 하루 이격 급변 점프.
|
| 109 |
+
return_state=True면 (sells, jumps, state) 반환. state=현재(마지막) 단계/이격.
|
| 110 |
고점 = '최근 PEAK_WINDOW(252) 거래일 내 최고점' (트레일링).
|
| 111 |
단계: flagON(대기) -> 1차(확정) -> 2차flagON(대기) -> 2차매도(확정)
|
| 112 |
- 평소: 직전 단계보다 이격 MIN_DEEPEN(2.5%p)+ 더 깊으면 다음 단계
|
|
|
|
| 182 |
sells.append({'i': t, 'price': st, 'div': div, 'date': dates[t]})
|
| 183 |
sold = True
|
| 184 |
prev_div = div
|
| 185 |
+
if return_state:
|
| 186 |
+
last = n - 1
|
| 187 |
+
cur_div = (float(stock[last]) / float(twpk[last]) - 1) \
|
| 188 |
+
- ((float(index[last]) / float(twip[last]) - 1) if twip[last] else 0.0)
|
| 189 |
+
state = {'stage': stage, 'stage_name': _SNAME.get(stage, '?'),
|
| 190 |
+
'div': cur_div, 'sold': sold}
|
| 191 |
+
return sells, jumps, state
|
| 192 |
return sells, jumps
|
| 193 |
|
| 194 |
|
|
|
|
| 229 |
|
| 230 |
def load_one(ticker, market):
|
| 231 |
try:
|
| 232 |
+
sdf = fdr.DataReader(ticker, DATA_START, _end_date())
|
| 233 |
except Exception:
|
| 234 |
return None
|
| 235 |
if not isinstance(sdf, pd.DataFrame) or 'Close' not in sdf.columns or len(sdf) == 0:
|
|
|
|
| 238 |
idf = None
|
| 239 |
for c in (idx_code, '^' + idx_code):
|
| 240 |
try:
|
| 241 |
+
t = fdr.DataReader(c, DATA_START, _end_date())
|
| 242 |
if isinstance(t, pd.DataFrame) and 'Close' in t.columns and len(t) > 0:
|
| 243 |
idf = t; break
|
| 244 |
except Exception:
|
|
|
|
| 270 |
|
| 271 |
def main():
|
| 272 |
print("=" * 88)
|
| 273 |
+
print(f"이격 재확인 백테스트 [lower-low] | {ANALYZE_FROM} ~ {_end_date()} | 종목 "
|
| 274 |
f"{sum(len(v) for v in TICKERS.values())}개")
|
| 275 |
print(f"규칙: 고점=최근{PEAK_WINDOW}일내최고 | 단계누적({MIN_DEEPEN*100:.1f}%p+) | 하루급변({DAILY_JUMP*100:.0f}%p)점프 | 1차~2차 22일내 | 회복시재시작")
|
| 276 |
print(f"채점: 관찰 {LOOK_AHEAD}일 | E율=240이탈(조기경보) | P율=매도가대비 {PROTECT_DROP*100:.0f}% 추가하락 회피")
|