glorifiedjx commited on
Commit
fa2c263
ยท
verified ยท
1 Parent(s): f05aed8

realtime data plz

Browse files
Files changed (1) hide show
  1. confirm_sell_backtest.py +111 -12
confirm_sell_backtest.py CHANGED
@@ -18,7 +18,9 @@ import sys, ssl
18
  import pandas as pd
19
  import numpy as np
20
  import FinanceDataReader as fdr
21
- from datetime import datetime, timedelta
 
 
22
 
23
  ssl._create_default_https_context = ssl._create_unverified_context
24
  if sys.platform == 'win32':
@@ -53,6 +55,17 @@ DAILY_JUMP = 0.10 # ํ•˜๋ฃจ๋งŒ์— ์ด๊ฒฉ์ด ์ „์ผๆฏ” ์ด๋งŒํผ(%p)+ ๊ธ‰
53
  # 3 = ๊ธฐ์กด(flagโ†’1์ฐจโ†’2์ฐจflagโ†’2์ฐจ๋งค๋„, ๊นŠ์–ด์ง 3๋ฒˆ). ์ค„์ด๋ฉด ๋” ์ผ์ฐ ์šธ๋ฆฌ์ง€๋งŒ ๋” ์ž์ฃผ ์šธ๋ฆผ.
54
  # 2 = flagโ†’1์ฐจโ†’๋งค๋„ (๊นŠ์–ด์ง 2๋ฒˆ) / 1 = flagโ†’๋งค๋„ (๊นŠ์–ด์ง 1๋ฒˆ, ๊ฐ€์žฅ ์ผ์ฐ/๊ฐ€์žฅ ์ž์ฃผ)
55
  CONFIRM_STAGES = 3
 
 
 
 
 
 
 
 
 
 
 
56
  PEAK_WINDOW = 252 # ๊ณ ์  ๊ธฐ์ค€ = ์ตœ๊ทผ N๊ฑฐ๋ž˜์ผ(252=1๋…„) ๋‚ด ์ตœ๊ณ ์  (์˜ค๋ž˜๋œ ๊ณ ์ ์— ์•ˆ ๋ฌถ์ž„)
57
  # CONFIRM_WINDOW ์ œ๊ฑฐ๋จ: 1์ฐจ->2์ฐจ ์‚ฌ์ด ์ผ์ˆ˜ ์ œํ•œ ์—†์Œ (๋ฉฐ์น ์ด ๊ฑธ๋ฆฌ๋“  ์—ฐ์‡„ ํ—ˆ์šฉ)
58
 
@@ -93,15 +106,20 @@ TREND_MIN_DAYS = 60 # '240์˜ฌ': ์ตœ๊ทผ N๊ฑฐ๋ž˜์ผ ์—ฐ์† 240์„  ์œ„
93
  TREND_MIN_GAP = 0.05 # '240์˜ฌ': ๋งค๋„์ผ ์ข…๊ฐ€๊ฐ€ 240์„  +5% ์ด์ƒ
94
 
95
  ANALYZE_FROM = '2020-01-01' # ์ฑ„์ (๋งค๋„์ง‘๊ณ„) ์‹œ์ž‘์ผ โ€” ์ด๊ฑด '์–ธ์ œ๋ถ€ํ„ฐ ๊ฒฐ๊ณผ๋ฅผ ๋ณผ์ง€'์ผ ๋ฟ
96
- ANALYZE_TO = None # None=์˜ค๋Š˜
97
 
98
  # โ˜… ๋ฐ์ดํ„ฐ ๋กœ๋”ฉ์€ ANALYZE_FROM ๊ณผ ๋ฌด๊ด€ํ•˜๊ฒŒ 'ํ•ญ์ƒ ์ถฉ๋ถ„ํžˆ ๊ณผ๊ฑฐ๋ถ€ํ„ฐ' ๋ถˆ๋Ÿฌ์˜จ๋‹ค.
99
  # (๊ณ ์ /์ด๊ฒฉ์€ ์ „์ฒด ๊ฐ€๊ฒฉ์ด๋ ฅ์œผ๋กœ ๊ณ„์‚ฐ๋ผ์•ผ ํ•˜๋ฏ€๋กœ. ANALYZE_FROM ๋งŒ ๋Šฆ์ถ”๋ฉด ๊ณ ์ ์„
100
  # ์ž˜๋ชป ์žก์•„ ๋งค๋„์‹œ์ ์ด ๋‹ฌ๋ผ์ง€๋Š” ๋ฒ„๊ทธ๊ฐ€ ์ƒ๊น€ -> ๊ทธ๋ž˜์„œ DATA_START ๋Š” ๊ณ ์ •.)
101
  DATA_START = '2018-01-01' # ๊ณ ์ •. ๋” ๊ณผ๊ฑฐ๋ฅผ ๋ณด๋ ค๋ฉด ์ด ๋‚ ์งœ๋งŒ ์•ž๋‹น๊ธฐ๋ฉด ๋จ.
102
 
103
- _to_dt = datetime.strptime(ANALYZE_TO, '%Y-%m-%d') if ANALYZE_TO else datetime.today()
104
- ANALYZE_TO = _to_dt.strftime('%Y-%m-%d')
 
 
 
 
 
105
 
106
 
107
  # =============================================
@@ -348,6 +366,82 @@ def find_confirmed_sells(stock, index, dates, start_pos, ma60=None, ma240=None,
348
  return sells, jumps, steps
349
 
350
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
351
  def in_240_run(stock, ma240, i):
352
  if i - TREND_MIN_DAYS + 1 < 0:
353
  return False
@@ -384,7 +478,7 @@ def protected(stock, i, price):
384
 
385
  def load_one(ticker, market):
386
  try:
387
- sdf = fdr.DataReader(ticker, DATA_START, ANALYZE_TO)
388
  except Exception:
389
  return None
390
  if not isinstance(sdf, pd.DataFrame) or 'Close' not in sdf.columns or len(sdf) == 0:
@@ -393,7 +487,7 @@ def load_one(ticker, market):
393
  idf = None
394
  for c in (idx_code, '^' + idx_code):
395
  try:
396
- t = fdr.DataReader(c, DATA_START, ANALYZE_TO)
397
  if isinstance(t, pd.DataFrame) and 'Close' in t.columns and len(t) > 0:
398
  idf = t; break
399
  except Exception:
@@ -442,7 +536,7 @@ def pct(a, b):
442
 
443
  def main():
444
  print("=" * 88)
445
- print(f"์ด๊ฒฉ ์žฌํ™•์ธ ๋ฐฑํ…Œ์ŠคํŠธ [lower-low] | {ANALYZE_FROM} ~ {ANALYZE_TO} | ์ข…๋ชฉ "
446
  f"{sum(len(v) for v in TICKERS.values())}๊ฐœ")
447
  if USE_TREND and USE_TREND_FLAT:
448
  cb = FLAT_COMBINE
@@ -454,10 +548,14 @@ def main():
454
  f"240{_b(FLAT_MIN_240,FLAT_MAX_240)}]")
455
  else:
456
  tf_s = "์ถ”์„ธํ•„ํ„ฐ=OFF"
457
- div_s = f"์ด๊ฒฉ๊ธฐ์ค€={DIV_THRESHOLD*100:.0f}%(๊ณ ์ •)"
458
- jmp_s = f"ํ•˜๋ฃจ๊ธ‰๋ณ€({DAILY_JUMP*100:.0f}%p)์ ํ”„"
459
- print(f"๊ทœ์น™: ๊ณ ์ =์ตœ๊ทผ{PEAK_WINDOW}์ผ๋‚ด์ตœ๊ณ  | {div_s} | ๋‹จ๊ณ„๋ˆ„์ ({MIN_DEEPEN*100:.1f}%p+, "
460
- f"๋งค๋„๊นŒ์ง€ {CONFIRM_STAGES+1}๋‹จ๊ณ„) | {jmp_s} | {tf_s}")
 
 
 
 
461
  print(f"์ฑ„์ : ๊ด€์ฐฐ {LOOK_AHEAD}์ผ | E์œจ=240์ดํƒˆ(์กฐ๊ธฐ๊ฒฝ๋ณด) | P์œจ=๋งค๋„๊ฐ€๋Œ€๋น„ {PROTECT_DROP*100:.0f}% ์ถ”๊ฐ€ํ•˜๋ฝ ํšŒํ”ผ")
462
  print("=" * 88)
463
 
@@ -483,7 +581,8 @@ def main():
483
  sl60 = _smoothed_slope(ma60, _sd, _sm) if ma60 is not None else None
484
  sl120 = _smoothed_slope(ma120, _sd, _sm) if ma120 is not None else None
485
  sl240 = _smoothed_slope(ma240, _sd, _sm) if ma240 is not None else None
486
- sells, jumps, steps = find_confirmed_sells(stock, index, r['dates'], r['start_pos'],
 
487
  ma60=ma60, ma240=ma240,
488
  low=r.get('low'), bbl=r.get('bbl'),
489
  ma240_est=r.get('ma240_est'), ma120=ma120)
 
18
  import pandas as pd
19
  import numpy as np
20
  import FinanceDataReader as fdr
21
+ from datetime import datetime, timedelta, timezone
22
+
23
+ _KST = timezone(timedelta(hours=9))
24
 
25
  ssl._create_default_https_context = ssl._create_unverified_context
26
  if sys.platform == 'win32':
 
55
  # 3 = ๊ธฐ์กด(flagโ†’1์ฐจโ†’2์ฐจflagโ†’2์ฐจ๋งค๋„, ๊นŠ์–ด์ง 3๋ฒˆ). ์ค„์ด๋ฉด ๋” ์ผ์ฐ ์šธ๋ฆฌ์ง€๋งŒ ๋” ์ž์ฃผ ์šธ๋ฆผ.
56
  # 2 = flagโ†’1์ฐจโ†’๋งค๋„ (๊นŠ์–ด์ง 2๋ฒˆ) / 1 = flagโ†’๋งค๋„ (๊นŠ์–ด์ง 1๋ฒˆ, ๊ฐ€์žฅ ์ผ์ฐ/๊ฐ€์žฅ ์ž์ฃผ)
57
  CONFIRM_STAGES = 3
58
+
59
+ # =============================================
60
+ # ๋งค๋„ ์—”์ง„ ์„ ํƒ
61
+ # 'STAGE' = ๊ธฐ์กด: ์ด๊ฒฉ flagโ†’1์ฐจโ†’2์ฐจflagโ†’2์ฐจ (๋‹จ๊ณ„๋ˆ„์ ). ํ—›์•Œ๋žŒ ์ ์ง€๋งŒ ํ›„ํ–‰(๋А๋ฆผ).
62
+ # 'RS_A4' = ์ƒˆ๊ฑฐ: RS์„ ์ด ์‹œ์žฅ๋ณด๋‹ค ์•ฝํ•ด์ง€๋ฉด(๋ฐ๋“œํฌ๋กœ์Šค) '๋ฌด์žฅ' -> A-4(์ถ”์„ธ์ฃฝ์Œ) ํ™•์ธ๋˜๋Š”
63
+ # ์ฆ‰์‹œ ๋งค๋„. ๋‹จ๊ณ„ ์•ˆ ๊ฑฐ์นจ -> ๋” ์ผ์ฐ. RS๋Š” ์„ ํ–‰์ง€ํ‘œ๋ผ 240 ๊นจ์ง€๊ธฐ ์ „์— ๊ฒฝ๊ณ .
64
+ # =============================================
65
+ ENGINE = 'STAGE' # 'STAGE' / 'RS_A4'
66
+ RS_MA_PERIOD = 20 # RS์„ (์ข…๋ชฉ/์ง€์ˆ˜)์˜ ์ด๋™ํ‰๊ท  ๊ธฐ๊ฐ„. RS < ์ด ํ‰๊ท ์ด๋ฉด ๋ฐ๋“œํฌ๋กœ์Šค(์•ฝํ™”)
67
+ RS_PERSIST = 3 # RS๊ฐ€ ์ด๋งŒํผ(๊ฑฐ๋ž˜์ผ) ์—ฐ์† ์•ฝํ•ด์•ผ '๋ฌด์žฅ' (ํ•˜๋ฃจ ๋…ธ์ด์ฆˆ ๋ฐฉ์ง€)
68
+ RS_CONFIRM = 'A4' # 'A4'=A-4 ์ถ”์„ธํ•„ํ„ฐ ํ™•์ธ๋ผ์•ผ ๋งค๋„ / 'NONE'=RS ๋ฐ๋“œํฌ๋กœ์Šค๋งŒ์œผ๋กœ ๋งค๋„
69
  PEAK_WINDOW = 252 # ๊ณ ์  ๊ธฐ์ค€ = ์ตœ๊ทผ N๊ฑฐ๋ž˜์ผ(252=1๋…„) ๋‚ด ์ตœ๊ณ ์  (์˜ค๋ž˜๋œ ๊ณ ์ ์— ์•ˆ ๋ฌถ์ž„)
70
  # CONFIRM_WINDOW ์ œ๊ฑฐ๋จ: 1์ฐจ->2์ฐจ ์‚ฌ์ด ์ผ์ˆ˜ ์ œํ•œ ์—†์Œ (๋ฉฐ์น ์ด ๊ฑธ๋ฆฌ๋“  ์—ฐ์‡„ ํ—ˆ์šฉ)
71
 
 
106
  TREND_MIN_GAP = 0.05 # '240์˜ฌ': ๋งค๋„์ผ ์ข…๊ฐ€๊ฐ€ 240์„  +5% ์ด์ƒ
107
 
108
  ANALYZE_FROM = '2020-01-01' # ์ฑ„์ (๋งค๋„์ง‘๊ณ„) ์‹œ์ž‘์ผ โ€” ์ด๊ฑด '์–ธ์ œ๋ถ€ํ„ฐ ๊ฒฐ๊ณผ๋ฅผ ๋ณผ์ง€'์ผ ๋ฟ
109
+ ANALYZE_TO = None # None=์˜ค๋Š˜(๋งค๋ฒˆ ํ˜ธ์ถœ์‹œ์  KST ๊ธฐ์ค€). ํŠน์ •์ผ ๊ณ ์ •ํ•˜๋ ค๋ฉด 'YYYY-MM-DD'.
110
 
111
  # โ˜… ๋ฐ์ดํ„ฐ ๋กœ๋”ฉ์€ ANALYZE_FROM ๊ณผ ๋ฌด๊ด€ํ•˜๊ฒŒ 'ํ•ญ์ƒ ์ถฉ๋ถ„ํžˆ ๊ณผ๊ฑฐ๋ถ€ํ„ฐ' ๋ถˆ๋Ÿฌ์˜จ๋‹ค.
112
  # (๊ณ ์ /์ด๊ฒฉ์€ ์ „์ฒด ๊ฐ€๊ฒฉ์ด๋ ฅ์œผ๋กœ ๊ณ„์‚ฐ๋ผ์•ผ ํ•˜๋ฏ€๋กœ. ANALYZE_FROM ๋งŒ ๋Šฆ์ถ”๋ฉด ๊ณ ์ ์„
113
  # ์ž˜๋ชป ์žก์•„ ๋งค๋„์‹œ์ ์ด ๋‹ฌ๋ผ์ง€๋Š” ๋ฒ„๊ทธ๊ฐ€ ์ƒ๊น€ -> ๊ทธ๋ž˜์„œ DATA_START ๋Š” ๊ณ ์ •.)
114
  DATA_START = '2018-01-01' # ๊ณ ์ •. ๋” ๊ณผ๊ฑฐ๋ฅผ ๋ณด๋ ค๋ฉด ์ด ๋‚ ์งœ๋งŒ ์•ž๋‹น๊ธฐ๋ฉด ๋จ.
115
 
116
+
117
+ def _end_date():
118
+ """๋ฐ์ดํ„ฐ ๋๋‚ ์งœ. ANALYZE_TO ๊ฐ€ None ์ด๋ฉด '์ง€๊ธˆ KST ์˜ค๋Š˜'์„ ๋งค๋ฒˆ ์ƒˆ๋กœ ๊ณ„์‚ฐ
119
+ (์•ฑ์ด ๋ฉฐ์น ์งธ ์ผœ์ ธ ์žˆ์–ด๋„ ํ•ญ์ƒ ์ตœ์‹  ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๋„๋ก)."""
120
+ if ANALYZE_TO:
121
+ return ANALYZE_TO
122
+ return datetime.now(_KST).strftime('%Y-%m-%d')
123
 
124
 
125
  # =============================================
 
366
  return sells, jumps, steps
367
 
368
 
369
+ def find_rs_a4_sells(stock, index, dates, start_pos, ma60=None, ma240=None,
370
+ low=None, bbl=None, ma240_est=None, ma120=None):
371
+ """RS_A4 ์—”์ง„: RS์„ (์ข…๋ชฉ/์ง€์ˆ˜)์ด ์‹œ์žฅ๋ณด๋‹ค ์•ฝํ•ด์ง€๋ฉด(RS<RS_MA, RS_PERSIST์ผ ์ง€์†) '๋ฌด์žฅ',
372
+ ๊ทธ ์ƒํƒœ์—์„œ A-4 ์ถ”์„ธํ•„ํ„ฐ๊ฐ€ ํ™•์ธ๋˜๋Š” ์ฆ‰์‹œ ์ „๋Ÿ‰๋งค๋„. ๋‹จ๊ณ„ ์•ˆ ๊ฑฐ์นจ -> ์ผ์ฐ ์šด๋‹ค.
373
+ ๋ฐ˜ํ™˜์€ STAGE ์—”์ง„๊ณผ ๋™์ผ ํ˜•์‹ (sells, jumps, steps)."""
374
+ n = len(stock)
375
+ twpk, twip = _trailing_peaks(stock, index, PEAK_WINDOW)
376
+
377
+ flat_slopes = None
378
+ if USE_TREND_FLAT:
379
+ flat_slopes = {}
380
+ for ln, arr in ((60, ma60), (120, ma120), (240, ma240)):
381
+ if arr is not None:
382
+ flat_slopes[ln] = _smoothed_slope(arr, FLAT_SLOPE_DAYS, FLAT_SMOOTH)
383
+
384
+ # RS์„ ๊ณผ ๊ทธ ์ด๋™ํ‰๊ท 
385
+ rs = np.array([stock[t] / index[t] if index[t] else np.nan for t in range(n)])
386
+ rs_ma = pd.Series(rs).rolling(RS_MA_PERIOD).mean().values
387
+ rs_weak = np.array([(not np.isnan(rs_ma[t])) and rs[t] < rs_ma[t] for t in range(n)])
388
+
389
+ sells = []; jumps = []; steps = []
390
+ def _step(t, name, div, note=''):
391
+ if t >= start_pos:
392
+ steps.append({'date': dates[t], 'name': name, 'div': div, 'note': note})
393
+
394
+ def _gate(t):
395
+ if ma240 is None:
396
+ return True, ''
397
+ return trend_ok(t, stock, ma240, ma60, ma120, flat_slopes)
398
+
399
+ armed = False; armed_date = None; sold = False; weak_run = 0
400
+ for t in range(n):
401
+ div = (stock[t] / twpk[t] - 1) - ((index[t] / twip[t] - 1) if twip[t] else 0.0)
402
+
403
+ if rs_weak[t]:
404
+ weak_run += 1
405
+ else:
406
+ # RS๊ฐ€ ๋‹ค์‹œ ์‹œ์žฅ๋ณด๋‹ค ๊ฐ•ํ•ด์ง -> ๋ฌด์žฅ ํ•ด์ œ / ๋งค๋„์ƒํƒœ ๋ฆฌ์…‹
407
+ if armed and t >= start_pos:
408
+ _step(t, '๋ฌด์žฅ ํ•ด์ œ(RS ํšŒ๋ณต)', div)
409
+ armed = False; weak_run = 0; sold = False
410
+ continue
411
+
412
+ # RS_PERSIST์ผ ์—ฐ์† ์•ฝํ•˜๋ฉด ๋ฌด์žฅ
413
+ if not armed and weak_run >= RS_PERSIST:
414
+ armed = True; armed_date = dates[t]
415
+ rsd = (rs[t] / rs_ma[t] - 1) * 100
416
+ _step(t, '๋ฌด์žฅ(RS ๋ฐ๋“œํฌ๋กœ์Šค)', div, f'RS {rsd:.1f}% < MA{RS_MA_PERIOD}')
417
+
418
+ if armed and not sold:
419
+ ok, why = (_gate(t) if RS_CONFIRM == 'A4' else (True, 'RS๋‹จ๋…'))
420
+ if ok:
421
+ if t >= start_pos:
422
+ est = bool(ma240_est[t]) if ma240_est is not None else False
423
+ sells.append({'i': t, 'price': float(stock[t]), 'div': div,
424
+ 'date': dates[t], 'trend': why,
425
+ 'via': f'RS๋ฌด์žฅ({armed_date})', 'est': est})
426
+ _step(t, '์ „๋Ÿ‰๋งค๋„ โ˜…๋ฐœ๋™', div,
427
+ f'RS๋ฌด์žฅ ํ›„ A-4ํ™•์ธ' if RS_CONFIRM == 'A4' else 'RS ๋ฐ๋“œํฌ๋กœ์Šค')
428
+ sold = True
429
+ else:
430
+ pass # ๋ฌด์žฅ๋์ง€๋งŒ A-4 ์•„์ง -> ๋Œ€๊ธฐ (๋‹ค์Œ๋‚  ๋˜ ํ™•์ธ)
431
+
432
+ # ํ˜„์žฌ ์ƒํƒœ
433
+ last = n - 1
434
+ if not sold:
435
+ div = (stock[last] / twpk[last] - 1) - ((index[last] / twip[last] - 1) if twip[last] else 0.0)
436
+ if armed:
437
+ ok, why = (_gate(last) if RS_CONFIRM == 'A4' else (True, ''))
438
+ note = ('A-4 ํ™•์ธ ๋Œ€๊ธฐ์ค‘ (' + why + ')') if RS_CONFIRM == 'A4' else 'RS๋‹จ๋…'
439
+ _step(last, '[ํ˜„์žฌ] ๋ฌด์žฅ๋จ(๋งค๋„ ๋Œ€๊ธฐ)', div, note)
440
+ else:
441
+ _step(last, '[ํ˜„์žฌ] ๊ด€๋ง (RS ์•„์ง ์‹œ์žฅ๋ณด๋‹ค ์•ˆ ์•ฝํ•จ)', div, '')
442
+ return sells, jumps, steps
443
+
444
+
445
  def in_240_run(stock, ma240, i):
446
  if i - TREND_MIN_DAYS + 1 < 0:
447
  return False
 
478
 
479
  def load_one(ticker, market):
480
  try:
481
+ sdf = fdr.DataReader(ticker, DATA_START, _end_date())
482
  except Exception:
483
  return None
484
  if not isinstance(sdf, pd.DataFrame) or 'Close' not in sdf.columns or len(sdf) == 0:
 
487
  idf = None
488
  for c in (idx_code, '^' + idx_code):
489
  try:
490
+ t = fdr.DataReader(c, DATA_START, _end_date())
491
  if isinstance(t, pd.DataFrame) and 'Close' in t.columns and len(t) > 0:
492
  idf = t; break
493
  except Exception:
 
536
 
537
  def main():
538
  print("=" * 88)
539
+ print(f"์ด๊ฒฉ ์žฌํ™•์ธ ๋ฐฑํ…Œ์ŠคํŠธ [lower-low] | {ANALYZE_FROM} ~ {_end_date()} | ์ข…๋ชฉ "
540
  f"{sum(len(v) for v in TICKERS.values())}๊ฐœ")
541
  if USE_TREND and USE_TREND_FLAT:
542
  cb = FLAT_COMBINE
 
548
  f"240{_b(FLAT_MIN_240,FLAT_MAX_240)}]")
549
  else:
550
  tf_s = "์ถ”์„ธํ•„ํ„ฐ=OFF"
551
+ if ENGINE == 'RS_A4':
552
+ rs_confirm = 'A-4ํ™•์ธ' if RS_CONFIRM == 'A4' else 'RS๋‹จ๋…'
553
+ print(f"์—”์ง„=RS_A4 | RS์„ <MA{RS_MA_PERIOD} {RS_PERSIST}์ผ์—ฐ์† ๋ฌด์žฅ -> {rs_confirm} ์ฆ‰์‹œ๋งค๋„ | {tf_s}")
554
+ else:
555
+ div_s = f"์ด๊ฒฉ๊ธฐ์ค€={DIV_THRESHOLD*100:.0f}%(๊ณ ์ •)"
556
+ jmp_s = f"ํ•˜๋ฃจ๊ธ‰๋ณ€({DAILY_JUMP*100:.0f}%p)์ ํ”„"
557
+ print(f"์—”์ง„=STAGE | ๊ณ ์ =์ตœ๊ทผ{PEAK_WINDOW}์ผ๋‚ด์ตœ๊ณ  | {div_s} | ๋‹จ๊ณ„๋ˆ„์ ({MIN_DEEPEN*100:.1f}%p+, "
558
+ f"๋งค๋„๊นŒ์ง€ {CONFIRM_STAGES+1}๋‹จ๊ณ„) | {jmp_s} | {tf_s}")
559
  print(f"์ฑ„์ : ๊ด€์ฐฐ {LOOK_AHEAD}์ผ | E์œจ=240์ดํƒˆ(์กฐ๊ธฐ๊ฒฝ๋ณด) | P์œจ=๋งค๋„๊ฐ€๋Œ€๋น„ {PROTECT_DROP*100:.0f}% ์ถ”๊ฐ€ํ•˜๋ฝ ํšŒํ”ผ")
560
  print("=" * 88)
561
 
 
581
  sl60 = _smoothed_slope(ma60, _sd, _sm) if ma60 is not None else None
582
  sl120 = _smoothed_slope(ma120, _sd, _sm) if ma120 is not None else None
583
  sl240 = _smoothed_slope(ma240, _sd, _sm) if ma240 is not None else None
584
+ _engine = find_rs_a4_sells if ENGINE == 'RS_A4' else find_confirmed_sells
585
+ sells, jumps, steps = _engine(stock, index, r['dates'], r['start_pos'],
586
  ma60=ma60, ma240=ma240,
587
  low=r.get('low'), bbl=r.get('bbl'),
588
  ma240_est=r.get('ma240_est'), ma120=ma120)