Spaces:
Running
Running
RS_M60_final
Browse files- confirm_sell_backtest.py +224 -55
confirm_sell_backtest.py
CHANGED
|
@@ -31,16 +31,32 @@ if sys.platform == 'win32':
|
|
| 31 |
# =============================================
|
| 32 |
TICKERS = {
|
| 33 |
'KOSPI': [
|
| 34 |
-
'005930', '000660', '373220', '207940',
|
| 35 |
-
|
| 36 |
-
'
|
| 37 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 38 |
],
|
| 39 |
'KOSDAQ': [
|
| 40 |
-
'247540', '086520', '196170', '028300', '348370',
|
| 41 |
-
'058470', '068760', '263750', '035900', '277810',
|
| 42 |
-
'041510', '035760', '112040', '293490', '145020',
|
| 43 |
-
'039030', '240810', '357780',
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 44 |
],
|
| 45 |
}
|
| 46 |
|
|
@@ -54,7 +70,7 @@ DAILY_JUMP = 0.10 # ํ๋ฃจ๋ง์ ์ด๊ฒฉ์ด ์ ์ผๆฏ ์ด๋งํผ(%p)+ ๊ธ
|
|
| 54 |
# --- ๋จ๊ณ ์ ์์ก์ด: flag ON ํ '๋ช ๋ฒ ๋ ๊น์ด์ ธ์ผ' ์ ๋๋งค๋๊ฐ ๋ฐ๋ํ๋ ---
|
| 55 |
# 3 = ๊ธฐ์กด(flagโ1์ฐจโ2์ฐจflagโ2์ฐจ๋งค๋, ๊น์ด์ง 3๋ฒ). ์ค์ด๋ฉด ๋ ์ผ์ฐ ์ธ๋ฆฌ์ง๋ง ๋ ์์ฃผ ์ธ๋ฆผ.
|
| 56 |
# 2 = flagโ1์ฐจโ๋งค๋ (๊น์ด์ง 2๋ฒ) / 1 = flagโ๋งค๋ (๊น์ด์ง 1๋ฒ, ๊ฐ์ฅ ์ผ์ฐ/๊ฐ์ฅ ์์ฃผ)
|
| 57 |
-
CONFIRM_STAGES =
|
| 58 |
|
| 59 |
# =============================================
|
| 60 |
# ๋งค๋ ์์ง ์ ํ
|
|
@@ -62,10 +78,37 @@ CONFIRM_STAGES = 3
|
|
| 62 |
# 'RS_A4' = ์๊ฑฐ: RS์ ์ด ์์ฅ๋ณด๋ค ์ฝํด์ง๋ฉด(๋ฐ๋ํฌ๋ก์ค) '๋ฌด์ฅ' -> A-4(์ถ์ธ์ฃฝ์) ํ์ธ๋๋
|
| 63 |
# ์ฆ์ ๋งค๋. ๋จ๊ณ ์ ๊ฑฐ์นจ -> ๋ ์ผ์ฐ. RS๋ ์ ํ์งํ๋ผ 240 ๊นจ์ง๊ธฐ ์ ์ ๊ฒฝ๊ณ .
|
| 64 |
# =============================================
|
| 65 |
-
ENGINE = '
|
| 66 |
RS_MA_PERIOD = 20 # RS์ (์ข
๋ชฉ/์ง์)์ ์ด๋ํ๊ท ๊ธฐ๊ฐ. RS < ์ด ํ๊ท ์ด๋ฉด ๋ฐ๋ํฌ๋ก์ค(์ฝํ)
|
|
|
|
|
|
|
|
|
|
| 67 |
RS_PERSIST = 3 # RS๊ฐ ์ด๋งํผ(๊ฑฐ๋์ผ) ์ฐ์ ์ฝํด์ผ '๋ฌด์ฅ' (ํ๋ฃจ ๋
ธ์ด์ฆ ๋ฐฉ์ง)
|
| 68 |
-
RS_CONFIRM = '
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 69 |
PEAK_WINDOW = 252 # ๊ณ ์ ๊ธฐ์ค = ์ต๊ทผ N๊ฑฐ๋์ผ(252=1๋
) ๋ด ์ต๊ณ ์ (์ค๋๋ ๊ณ ์ ์ ์ ๋ฌถ์)
|
| 70 |
# CONFIRM_WINDOW ์ ๊ฑฐ๋จ: 1์ฐจ->2์ฐจ ์ฌ์ด ์ผ์ ์ ํ ์์ (๋ฉฐ์น ์ด ๊ฑธ๋ฆฌ๋ ์ฐ์ ํ์ฉ)
|
| 71 |
|
|
@@ -77,7 +120,7 @@ PEAK_WINDOW = 252 # ๊ณ ์ ๊ธฐ์ค = ์ต๊ทผ N๊ฑฐ๋์ผ(252=1๋
) ๋ด ์ต
|
|
| 77 |
USE_TREND = True # ์ถ์ธํํฐ ์ ์ฒด on/off (๊บผ์ง๋ฉด ํํฐ ์์)
|
| 78 |
|
| 79 |
# ๊ณตํต ์ ์ : 60์ ์ด 240์ ๋ํ ํ ์ด๋งํผ(๊ฑฐ๋์ผ) ์ง๋์ผ ๋งค๋ ํ์ฉ
|
| 80 |
-
RUN_MIN_DAYS =
|
| 81 |
|
| 82 |
# 240์ ์ถ์ : 240์ผ์น ๋ฐ์ดํฐ๊ฐ ์์ผ๋ฉด(์์ฅ์ด๊ธฐ ๋ฑ) ์๋ ๋งํผ ์ต์ฅ ํ๊ท ์ผ๋ก ๋์ฒด
|
| 83 |
ESTIMATE_MA240 = True # True๋ฉด 240์ผ ๋ฏธ๋ง์ด์ด๋ ์ถ์ ํด์ ํ์ (๋งค๋ ๋ผ์ธ์ [240์ถ์ ] ํ์)
|
|
@@ -94,16 +137,20 @@ FLAT_MAX_60 = 0.00 # 60์ ๊ธฐ์ธ๊ธฐ ์ํ (โค0%=๊บพ์ฌ ๋ด๋ ค๊ฐ๊ฑฐ
|
|
| 94 |
FLAT_MIN_120 = -9.0 # 120์ ๊ธฐ์ธ๊ธฐ ํํ (-9=ํํ์์)
|
| 95 |
FLAT_MAX_120 = 0.05 # 120์ ๊ธฐ์ธ๊ธฐ ์ํ
|
| 96 |
FLAT_MIN_240 = 0.00 # 240์ ๊ธฐ์ธ๊ธฐ ํํ (0%=๋ง์ด๋์ค๋ฉด ๋๋ฌด ๋ฆ์ -> ์ ์ธ)
|
| 97 |
-
FLAT_MAX_240 = 0.04 # 240์ ๊ธฐ์ธ๊ธฐ ์ํ
|
| 98 |
FLAT_COMBINE = 'AND' # 'AND'(์ธ ์ ๋ค ๋ง์กฑ) / 'OR'(ํ๋๋ผ๋ ๋ง์กฑ)
|
| 99 |
|
| 100 |
-
SHOW_STEPS =
|
| 101 |
|
| 102 |
LOOK_AHEAD = 200 # ๋งค๋ ํ ๊ด์ฐฐ๊ธฐ๊ฐ(๊ฑฐ๋์ผ)
|
| 103 |
PROTECT_DROP = -0.10 # ๋งค๋๊ฐ ๋๋น ์ด๋งํผ ๋ ๋น ์ง๋ฉด '์ ํ ๊ฒ'
|
| 104 |
|
| 105 |
-
TREND_MIN_DAYS = 60 # '240์ฌ': ์ต๊ทผ N๊ฑฐ๋์ผ ์ฐ์ 240์ ์
|
| 106 |
-
TREND_MIN_GAP = 0.05 # '240์ฌ':
|
|
|
|
|
|
|
|
|
|
|
|
|
| 107 |
|
| 108 |
ANALYZE_FROM = '2020-01-01' # ์ฑ์ (๋งค๋์ง๊ณ) ์์์ผ โ ์ด๊ฑด '์ธ์ ๋ถํฐ ๊ฒฐ๊ณผ๋ฅผ ๋ณผ์ง'์ผ ๋ฟ
|
| 109 |
ANALYZE_TO = None # None=์ค๋(๋งค๋ฒ ํธ์ถ์์ KST ๊ธฐ์ค). ํน์ ์ผ ๊ณ ์ ํ๋ ค๋ฉด 'YYYY-MM-DD'.
|
|
@@ -359,10 +406,18 @@ def find_confirmed_sells(stock, index, dates, start_pos, ma60=None, ma240=None,
|
|
| 359 |
tail = ' (๋ค์: ์ ๋๋งค๋!)' if stage == SELL_STAGE - 1 else ''
|
| 360 |
nm = f'{stage}๋จ๊ณ / ๋งค๋๊น์ง {SELL_STAGE}๋จ๊ณ{tail}'
|
| 361 |
cur = float(stock[last] / twpk[last] - 1) - ((float(index[last] / twip[last] - 1)) if twip[last] else 0.0)
|
| 362 |
-
|
| 363 |
-
|
| 364 |
-
|
| 365 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 366 |
return sells, jumps, steps
|
| 367 |
|
| 368 |
|
|
@@ -381,10 +436,14 @@ def find_rs_a4_sells(stock, index, dates, start_pos, ma60=None, ma240=None,
|
|
| 381 |
if arr is not None:
|
| 382 |
flat_slopes[ln] = _smoothed_slope(arr, FLAT_SLOPE_DAYS, FLAT_SMOOTH)
|
| 383 |
|
| 384 |
-
# RS์
|
| 385 |
-
|
| 386 |
-
|
| 387 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 388 |
|
| 389 |
sells = []; jumps = []; steps = []
|
| 390 |
def _step(t, name, div, note=''):
|
|
@@ -396,46 +455,153 @@ def find_rs_a4_sells(stock, index, dates, start_pos, ma60=None, ma240=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
|
|
|
|
|
|
|
| 410 |
continue
|
| 411 |
|
| 412 |
-
# RS_PERSIST์ผ ์ฐ์ ์ฝํ๋ฉด ๋ฌด์ฅ
|
| 413 |
-
if not armed and weak_run >= RS_PERSIST:
|
| 414 |
-
|
| 415 |
-
|
| 416 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 417 |
|
| 418 |
if armed and not sold:
|
| 419 |
-
ok, why = (
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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 # ๋ฌด์ฅ๋์ง๋ง
|
| 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 = (
|
| 438 |
-
note =
|
| 439 |
_step(last, '[ํ์ฌ] ๋ฌด์ฅ๋จ(๋งค๋ ๋๊ธฐ)', div, note)
|
| 440 |
else:
|
| 441 |
_step(last, '[ํ์ฌ] ๊ด๋ง (RS ์์ง ์์ฅ๋ณด๋ค ์ ์ฝํจ)', div, '')
|
|
@@ -549,8 +715,10 @@ def main():
|
|
| 549 |
else:
|
| 550 |
tf_s = "์ถ์ธํํฐ=OFF"
|
| 551 |
if ENGINE == 'RS_A4':
|
| 552 |
-
rs_confirm = 'A-4
|
| 553 |
-
|
|
|
|
|
|
|
| 554 |
else:
|
| 555 |
div_s = f"์ด๊ฒฉ๊ธฐ์ค={DIV_THRESHOLD*100:.0f}%(๊ณ ์ )"
|
| 556 |
jmp_s = f"ํ๋ฃจ๊ธ๋ณ({DAILY_JUMP*100:.0f}%p)์ ํ"
|
|
@@ -648,22 +816,23 @@ def main():
|
|
| 648 |
else:
|
| 649 |
print(f" {tk} {market} - ๋งค๋ ์์")
|
| 650 |
|
| 651 |
-
# ---- ํ๋ฃจ ๊ธ๋ณ ์ ํ
|
| 652 |
-
|
| 653 |
-
|
| 654 |
-
|
| 655 |
-
|
| 656 |
-
|
| 657 |
-
|
| 658 |
-
|
| 659 |
-
|
| 660 |
-
|
| 661 |
-
|
| 662 |
-
|
| 663 |
-
|
| 664 |
-
|
| 665 |
-
|
| 666 |
-
|
|
|
|
| 667 |
|
| 668 |
|
| 669 |
if __name__ == '__main__':
|
|
|
|
| 31 |
# =============================================
|
| 32 |
TICKERS = {
|
| 33 |
'KOSPI': [
|
| 34 |
+
# '005930', '000660', '373220', '207940',
|
| 35 |
+
# '005380',
|
| 36 |
+
# '000270', '068270', '035420', '035720', '005490',
|
| 37 |
+
# '105560', '055550', '012330',
|
| 38 |
+
# '051910',
|
| 39 |
+
# '012450',
|
| 40 |
+
# '006400',
|
| 41 |
+
# '028260', '066570', '096770', '034730', '015760',
|
| 42 |
+
# '178920',
|
| 43 |
+
# '204320',
|
| 44 |
+
# '005250',
|
| 45 |
],
|
| 46 |
'KOSDAQ': [
|
| 47 |
+
# '247540', '086520', '196170', '028300', '348370',
|
| 48 |
+
# '058470', '068760', '263750', '035900', '277810',
|
| 49 |
+
# '041510', '035760', '112040', '293490', '145020',
|
| 50 |
+
# '039030', '240810', '357780',
|
| 51 |
+
# '403870',
|
| 52 |
+
# '121600',
|
| 53 |
+
# '399720',
|
| 54 |
+
# '277810',
|
| 55 |
+
# '257720',
|
| 56 |
+
# '017510',
|
| 57 |
+
# '389020',
|
| 58 |
+
# '195940',
|
| 59 |
+
'251370',
|
| 60 |
],
|
| 61 |
}
|
| 62 |
|
|
|
|
| 70 |
# --- ๋จ๊ณ ์ ์์ก์ด: flag ON ํ '๋ช ๋ฒ ๋ ๊น์ด์ ธ์ผ' ์ ๋๋งค๋๊ฐ ๋ฐ๋ํ๋ ---
|
| 71 |
# 3 = ๊ธฐ์กด(flagโ1์ฐจโ2์ฐจflagโ2์ฐจ๋งค๋, ๊น์ด์ง 3๋ฒ). ์ค์ด๋ฉด ๋ ์ผ์ฐ ์ธ๋ฆฌ์ง๋ง ๋ ์์ฃผ ์ธ๋ฆผ.
|
| 72 |
# 2 = flagโ1์ฐจโ๋งค๋ (๊น์ด์ง 2๋ฒ) / 1 = flagโ๋งค๋ (๊น์ด์ง 1๋ฒ, ๊ฐ์ฅ ์ผ์ฐ/๊ฐ์ฅ ์์ฃผ)
|
| 73 |
+
CONFIRM_STAGES = 0
|
| 74 |
|
| 75 |
# =============================================
|
| 76 |
# ๋งค๋ ์์ง ์ ํ
|
|
|
|
| 78 |
# 'RS_A4' = ์๊ฑฐ: RS์ ์ด ์์ฅ๋ณด๋ค ์ฝํด์ง๋ฉด(๋ฐ๋ํฌ๋ก์ค) '๋ฌด์ฅ' -> A-4(์ถ์ธ์ฃฝ์) ํ์ธ๋๋
|
| 79 |
# ์ฆ์ ๋งค๋. ๋จ๊ณ ์ ๊ฑฐ์นจ -> ๋ ์ผ์ฐ. RS๋ ์ ํ์งํ๋ผ 240 ๊นจ์ง๊ธฐ ์ ์ ๊ฒฝ๊ณ .
|
| 80 |
# =============================================
|
| 81 |
+
ENGINE = 'RS_A4' # 'STAGE' / 'RS_A4'
|
| 82 |
RS_MA_PERIOD = 20 # RS์ (์ข
๋ชฉ/์ง์)์ ์ด๋ํ๊ท ๊ธฐ๊ฐ. RS < ์ด ํ๊ท ์ด๋ฉด ๋ฐ๋ํฌ๋ก์ค(์ฝํ)
|
| 83 |
+
RS_SMOOTH = 5 # RS์ ์์ฒด๋ฅผ ์ด ์ผ์ EMA๋ก ๋ถ๋๋ฝ๊ฒ(ํฑ๋ ์ ๊ฑฐ). 1์ด๋ฉด smoothing ์ํจ.
|
| 84 |
+
RS_BUFFER = 0.02 # ๋ฐ๋ํฌ๋ก์ค ๋ฒํผ: RS๊ฐ MA๋ณด๋ค '์ด๋งํผ(2%) ํ์คํ ์๋'์ฌ์ผ ์ฝํ ์ธ์
|
| 85 |
+
# (RSยทMA ๋ฑ ๋ถ์ด์ 0.0001 ์ฐจ์ด๋ก ํกํก ๊ต์ฐจํ๋ ์ฆ์ ์๋ ๋ฐฉ์ง)
|
| 86 |
RS_PERSIST = 3 # RS๊ฐ ์ด๋งํผ(๊ฑฐ๋์ผ) ์ฐ์ ์ฝํด์ผ '๋ฌด์ฅ' (ํ๋ฃจ ๋
ธ์ด์ฆ ๋ฐฉ์ง)
|
| 87 |
+
RS_CONFIRM = 'MA60' # ๋ฌด์ฅ ํ '๋งค๋ ํ์ธ' ์ ํธ:
|
| 88 |
+
# 'A4' = ์ดํ์ ํํ(๋๋ฆผ/์์ , ์ฒ์ฒํ ์ฃฝ๋ ์ถ์ธ์ฉ)
|
| 89 |
+
# 'MA60' = ์ข
๊ฐ๊ฐ 60์ ๊นจ๋ฉด(๋น ๋ฆ! ๊ธ๋ฝ์ ๊ฐํจ) โ ๋ฆ๊ฒ ์ฐ๋ ๊ฑฐ ํด๊ฒฐ
|
| 90 |
+
# 'MA120' = ์ข
๊ฐ๊ฐ 120์ ๊นจ๋ฉด(์ค๊ฐ)
|
| 91 |
+
# 'NONE' = RS ๋ฐ๋ํฌ๋ก์ค๋ง์ผ๋ก(์ ์ผ ๋น ๋ฆ/์ ์ผ ์๋๋ฌ์)
|
| 92 |
+
CONFIRM_NEEDS_FLAT = 'MARGIN' # MA60/MA120 ํ์ธ์ ์ถ๊ฐ ๊ฒ์ดํธ (์ค๋ฅด๋ ์ค์ ๋งค๋ ๊ธ์ง):
|
| 93 |
+
# 'OFF' = ์ข
๊ฐ๋ง (๋น ๋ฅด์ง๋ง ์ค๋ฅผ ๋๋ ์ฐํ)
|
| 94 |
+
# 'SELF' = ํ์ธ์ ๊ธฐ์ธ๊ธฐ ์ฐ์ํฅ์ด๋ฉด ๊ธ์ง (๊ธฐ์ธ๊ธฐ ํํโ๋๋ฆผ)
|
| 95 |
+
# 'MARGIN' = ์ข
๊ฐ๊ฐ ํ์ธ์ ๋ณด๋ค CONFIRM_MARGIN ์๋์ฌ์ผ (๋น ๋ฆ+๋๋ฆผ๋ฌด์)
|
| 96 |
+
# 'MARGIN+240' = MARGIN + 240์ ๊ฐํ๋ฅธ์์น(>FLAT_MAX_240)์ด๋ฉด ๊ธ์ง โ ์ถ์ฒ
|
| 97 |
+
# '240' = 240์ ์ด ํํ/๊บพ์์ด์ด์ผ (๋ ์๊ฒฉ)
|
| 98 |
+
# (RS_CONFIRM='A4'/'NONE'์ผ ๋ ์ด ์ค์ ๋ฌด์)
|
| 99 |
+
CONFIRM_MARGIN = 0.035 # 'MARGIN' ๋ชจ๋์์: ์ข
๊ฐ๊ฐ ํ์ธ์ ๋ณด๋ค ์ด๋งํผ(3%) ์๋์ฌ์ผ '๋ถ๊ดด'๋ก ์ธ์ .
|
| 100 |
+
# ์ ๊น ๋๋ฆผ(์ ์ด์ง ์ค์นจ)์ ๋ฌด์, ์ง์ง ๊ธ๋ฝ๋ง. ๊ธฐ์ธ๊ธฐ ์ ๊ธฐ๋ค๋ ค์ ๋น ๋ฆ.
|
| 101 |
+
SELL_ONCE = True # ์ฒซ ๋งค๋ ํ์ '์ง์ง ์ถ์ธ๋ณต๊ท'๊น์ง ์ฌ๋ฌด์ฅ ๊ธ์ง.
|
| 102 |
+
# ๋จ์ด์ง๋ ์ข
๋ชฉ์ด -30/-40/-50/-80%์ ๊ณ์ ๋ ์ฐ๋ ํฑ๋ ์ ๊ฑฐ.
|
| 103 |
+
RELOCK_LINE = 240 # ์ ๊ธํด์ ๊ธฐ์ค์ : 240=ํ์ค(ํญ๋ฝ์ฃผ ๋ด๋ด ์ ๊น) / 120=๋์จ(๋นจ๋ฆฌ ํ๋ฆผ)
|
| 104 |
+
# ํญ๋ฝ ์ค์ 120์ ์ด ์ฃผ๊ฐ์ ๋ฐ์ง ๋ถ์ด ์ ๊น ๋ฐ๋ฑ์๋ ํ๋ ค๋ฒ๋ฆผ -> 240 ๊ถ์ฅ
|
| 105 |
+
RELOCK_MIN_DAYS = 60 # + ์ฒซ ๋งค๋ ํ ์ต์ ์ด ์ผ์๋ ๋ฌด์กฐ๊ฑด ์ ๊ธ(๋ ๋ค ์ถฉ์กฑํด์ผ ํด์ )
|
| 106 |
+
NO_ARM_BELOW_240 = -0.10 # ์ข
๊ฐ๊ฐ 240์ ๋ณด๋ค ์ด๋งํผ(-10%) ๋ ์๋๋ฉด '๋ฌด์ฅ ๊ธ์ง'.
|
| 107 |
+
# ์ด๋ฏธ ์ถ์ธ ๋ฌด๋์ง(240 ํ์ฐธ ์๋) ์ข
๋ชฉ์ ์ตํ๋ณด๋ฃจ ๋์ ์๋.
|
| 108 |
+
# None ์ด๋ฉด ์ด ํํฐ ๋(240 ์๋์ฌ๋ ๋ฌด์ฅ ํ์ฉ).
|
| 109 |
+
NO_ARM_DIV_BELOW = -0.30 # ์ด๊ฒฉ(๊ณ ์ ๋๋น ๋ํญ)์ด ์ด๋ฏธ ์ด๋งํผ(-25%) ๋๊ฒ ๊น์ผ๋ฉด '๋ฌด์ฅ ๊ธ์ง'.
|
| 110 |
+
# 240์ ์ ํญ๋ฝ์ฃผ ๋ฐ๋ผ ๋ฐ๋ฅ๊น์ง ๋ด๋ ค์์ ๋ชป ๊ฑฐ๋ฆ -> '๊ณ ์ ๋๋น'๋ก ๋ง์.
|
| 111 |
+
# ์ด๋ฏธ -50/-80% ๋น ์ง ์์ฒด์ 'ํ์๋ผ' ์ ํจ. None=ํํฐ ๋.
|
| 112 |
PEAK_WINDOW = 252 # ๊ณ ์ ๊ธฐ์ค = ์ต๊ทผ N๊ฑฐ๋์ผ(252=1๋
) ๋ด ์ต๊ณ ์ (์ค๋๋ ๊ณ ์ ์ ์ ๋ฌถ์)
|
| 113 |
# CONFIRM_WINDOW ์ ๊ฑฐ๋จ: 1์ฐจ->2์ฐจ ์ฌ์ด ์ผ์ ์ ํ ์์ (๋ฉฐ์น ์ด ๊ฑธ๋ฆฌ๋ ์ฐ์ ํ์ฉ)
|
| 114 |
|
|
|
|
| 120 |
USE_TREND = True # ์ถ์ธํํฐ ์ ์ฒด on/off (๊บผ์ง๋ฉด ํํฐ ์์)
|
| 121 |
|
| 122 |
# ๊ณตํต ์ ์ : 60์ ์ด 240์ ๋ํ ํ ์ด๋งํผ(๊ฑฐ๋์ผ) ์ง๋์ผ ๋งค๋ ํ์ฉ
|
| 123 |
+
RUN_MIN_DAYS = 40 # 60์ ์ด 240์ ๋ํ ํ ๊ฒฝ๊ณผ์ผ (๋ง ๋ํ ์งํ=240์ ๋๋ฌด ๊ทผ์ฒ๋ผ ์๋ฏธ์์)
|
| 124 |
|
| 125 |
# 240์ ์ถ์ : 240์ผ์น ๋ฐ์ดํฐ๊ฐ ์์ผ๋ฉด(์์ฅ์ด๊ธฐ ๋ฑ) ์๋ ๋งํผ ์ต์ฅ ํ๊ท ์ผ๋ก ๋์ฒด
|
| 126 |
ESTIMATE_MA240 = True # True๋ฉด 240์ผ ๋ฏธ๋ง์ด์ด๋ ์ถ์ ํด์ ํ์ (๋งค๋ ๋ผ์ธ์ [240์ถ์ ] ํ์)
|
|
|
|
| 137 |
FLAT_MIN_120 = -9.0 # 120์ ๊ธฐ์ธ๊ธฐ ํํ (-9=ํํ์์)
|
| 138 |
FLAT_MAX_120 = 0.05 # 120์ ๊ธฐ์ธ๊ธฐ ์ํ
|
| 139 |
FLAT_MIN_240 = 0.00 # 240์ ๊ธฐ์ธ๊ธฐ ํํ (0%=๋ง์ด๋์ค๋ฉด ๋๋ฌด ๋ฆ์ -> ์ ์ธ)
|
| 140 |
+
FLAT_MAX_240 = 0.04 # 240์ ๊ธฐ์ธ๊ธฐ ์ํ (์ด๋ณด๋ค ๊ฐํ๋ฅด๊ฒ ์ค๋ฅด๋ฉด=์์น์ถ์ธ ํ๋ณตํ ๋๋ฆผ -> ๋งค๋X)
|
| 141 |
FLAT_COMBINE = 'AND' # 'AND'(์ธ ์ ๋ค ๋ง์กฑ) / 'OR'(ํ๋๋ผ๋ ๋ง์กฑ)
|
| 142 |
|
| 143 |
+
SHOW_STEPS = False # True๋ฉด ๋งค๋๋ง๋ค [๋จ๊ณ ์์ธ](flag/1์ฐจ/2์ฐจ ์ธ์ ์ด๋ป๊ฒ) ์ถ๋ ฅ
|
| 144 |
|
| 145 |
LOOK_AHEAD = 200 # ๋งค๋ ํ ๊ด์ฐฐ๊ธฐ๊ฐ(๊ฑฐ๋์ผ)
|
| 146 |
PROTECT_DROP = -0.10 # ๋งค๋๊ฐ ๋๋น ์ด๋งํผ ๋ ๋น ์ง๋ฉด '์ ํ ๊ฒ'
|
| 147 |
|
| 148 |
+
TREND_MIN_DAYS = 60 # '240์ฌ'(๊ฐํ ์์น์ถ์ธ): ์ต๊ทผ N๊ฑฐ๋์ผ ์ฐ์ 240์ ์
|
| 149 |
+
TREND_MIN_GAP = 0.05 # '240์ฌ': ์ข
๊ฐ๊ฐ 240์ +5% ์ด์
|
| 150 |
+
|
| 151 |
+
# ๊ฐํ ์์น์ถ์ธ(240์ฌ) ์ค์ด๋ฉด ๋งค๋ ๊ธ์ง โ ๊ธ๋ฑ์ฃผ๊ฐ ์์น ํ๋ณตํ์์ 60์ ์ ๊น ๊นจ๋
|
| 152 |
+
# '๋๋ฆผ'์ ๋ถ๊ดด๋ก ์ค์ธํ๋ false alarm ๋ฐฉ์ง. (240 ๊ธฐ์ธ๊ธฐ๋ณด๋ค ํผํผ: 60์ผ์ฐ์ 240์+5%๊ฐญ)
|
| 153 |
+
NO_SELL_STRONG_UPTREND = False # True๋ฉด in_240_run(๊ฐํ์์น) ์ ๋งค๋ ๋ณด๋ฅ
|
| 154 |
|
| 155 |
ANALYZE_FROM = '2020-01-01' # ์ฑ์ (๋งค๋์ง๊ณ) ์์์ผ โ ์ด๊ฑด '์ธ์ ๋ถํฐ ๊ฒฐ๊ณผ๋ฅผ ๋ณผ์ง'์ผ ๋ฟ
|
| 156 |
ANALYZE_TO = None # None=์ค๋(๋งค๋ฒ ํธ์ถ์์ KST ๊ธฐ์ค). ํน์ ์ผ ๊ณ ์ ํ๋ ค๋ฉด 'YYYY-MM-DD'.
|
|
|
|
| 406 |
tail = ' (๋ค์: ์ ๋๋งค๋!)' if stage == SELL_STAGE - 1 else ''
|
| 407 |
nm = f'{stage}๋จ๊ณ / ๋งค๋๊น์ง {SELL_STAGE}๋จ๊ณ{tail}'
|
| 408 |
cur = float(stock[last] / twpk[last] - 1) - ((float(index[last] / twip[last] - 1)) if twip[last] else 0.0)
|
| 409 |
+
trigger = ref_div - MIN_DEEPEN # ๋ค์ ๋จ๊ณ ๋ฐ๋ ์ด๊ฒฉ
|
| 410 |
+
need = cur - trigger # >0 ์ด๋ฉด ์ด๋งํผ ๋ ๊น์ด์ ธ์ผ ๋ค์ ๋จ๊ณ
|
| 411 |
+
# ํ์ฌ ์ด๊ฒฉ์ด '๋ฌด์ฅ๋ ์ต์ ์ (ref_div)'๋ณด๋ค ๋๋ ท์ด ์๋ก ํ๋ณต๋์ผ๋ฉด = ๋ฐ๋ฑ ์ค (์๋ฐ ์๋)
|
| 412 |
+
if cur > ref_div + MIN_DEEPEN:
|
| 413 |
+
nm = nm.replace(' (์ ๋๋งค๋ ์๋ฐ!)', '').replace(' (๋ค์: ์ ๋๋งค๋!)', '')
|
| 414 |
+
note = (f'๋ฐ๋ฑ ์ค โ ํ์ฌ ์ด๊ฒฉ {cur*100:.1f}%, ์ต์ {ref_div*100:.1f}%๊น์ง ๊ฐ๋ค ํ๋ณต. '
|
| 415 |
+
f'๋งค๋ํธ๋ฆฌ๊ฑฐ {trigger*100:.1f}% (๋ฆฌ์
์ ์ด๊ฒฉ {DIV_THRESHOLD*100:.0f}% ํ๋ณต ์)')
|
| 416 |
+
_step(last, f'[ํ์ฌ] {nm} ยท ๋ฐ๋ฑ ์ค', cur, note)
|
| 417 |
+
elif need > 0:
|
| 418 |
+
_step(last, f'[ํ์ฌ] {nm}', cur, f'๋ค์ ๋จ๊ณ๊น์ง {need*100:.1f}%p ๋ ํ๋ฝ ํ์')
|
| 419 |
+
else:
|
| 420 |
+
_step(last, f'[ํ์ฌ] {nm}', cur, '์กฐ๊ฑด ์ถฉ์กฑ์ํ(๋ค์๋ด ํ์ธ)')
|
| 421 |
return sells, jumps, steps
|
| 422 |
|
| 423 |
|
|
|
|
| 436 |
if arr is not None:
|
| 437 |
flat_slopes[ln] = _smoothed_slope(arr, FLAT_SLOPE_DAYS, FLAT_SMOOTH)
|
| 438 |
|
| 439 |
+
# RS์ (์ข
๋ชฉ/์ง์) -> ํฑ๋ ์ค์ด๋ ค EMA๋ก ๋ถ๋๋ฝ๊ฒ -> ๊ทธ ์ด๋ํ๊ท ๊ณผ ๋น๊ต(๋ฒํผ๋ฐด๋)
|
| 440 |
+
rs_raw = pd.Series([stock[t] / index[t] if index[t] else np.nan for t in range(n)])
|
| 441 |
+
rs_s = rs_raw.ewm(span=max(1, RS_SMOOTH), adjust=False).mean() if RS_SMOOTH > 1 else rs_raw
|
| 442 |
+
rs = rs_s.values
|
| 443 |
+
rs_ma = rs_s.rolling(RS_MA_PERIOD).mean().values
|
| 444 |
+
# ๋ฐ๋ํฌ๋ก์ค: RS๊ฐ MA๋ณด๋ค RS_BUFFER ๋งํผ 'ํ์คํ' ์๋์ฌ์ผ ์ฝํ ์ธ์ (์ค์นจ ๋ฌด์)
|
| 445 |
+
rs_weak = np.array([(not np.isnan(rs_ma[t])) and rs[t] < rs_ma[t] * (1 - RS_BUFFER)
|
| 446 |
+
for t in range(n)])
|
| 447 |
|
| 448 |
sells = []; jumps = []; steps = []
|
| 449 |
def _step(t, name, div, note=''):
|
|
|
|
| 455 |
return True, ''
|
| 456 |
return trend_ok(t, stock, ma240, ma60, ma120, flat_slopes)
|
| 457 |
|
| 458 |
+
def _flat_gate(line_no):
|
| 459 |
+
"""CONFIRM_NEEDS_FLAT์ ๋ฐ๋ผ ์ถ๊ฐ ์กฐ๊ฑด. (ํต๊ณผ์ฌ๋ถ, ์ฌ์ ๊ผฌ๋ฆฌํ) ๋ฐํ."""
|
| 460 |
+
def slope_at(ln, t):
|
| 461 |
+
arr = flat_slopes.get(ln) if flat_slopes else None
|
| 462 |
+
return arr[t] if (arr is not None and not np.isnan(arr[t])) else None
|
| 463 |
+
line_arr = {60: ma60, 120: ma120}.get(line_no)
|
| 464 |
+
if CONFIRM_NEEDS_FLAT == 'SELF':
|
| 465 |
+
def chk(t):
|
| 466 |
+
s = slope_at(line_no, t)
|
| 467 |
+
if s is None:
|
| 468 |
+
return True, ''
|
| 469 |
+
if s > 0: # ํ์ธ์ ์ด ์ฐ์ํฅ -> ๋งค๋ ๊ธ์ง
|
| 470 |
+
return False, f'{line_no}์ ์ฐ์ํฅ({s*100:+.1f}%)โ๋ณด๋ฅ'
|
| 471 |
+
return True, f'{line_no}์ ๊ธฐ์ธ๊ธฐ{s*100:+.1f}%'
|
| 472 |
+
return chk
|
| 473 |
+
if CONFIRM_NEEDS_FLAT in ('MARGIN', 'MARGIN+240'):
|
| 474 |
+
# ๊ธฐ์ธ๊ธฐ(ํํ) ๋์ ๋ง์ง: ์ข
๊ฐ๊ฐ ํ์ธ์ ๋ณด๋ค CONFIRM_MARGIN ํ์คํ ์๋์ฌ์ผ ๋ฐ๋.
|
| 475 |
+
# ์ ๊น ๋๋ฆผ(์ ์ด์ง ์ค์นจ)=๋ฌด์, ์ง์ง ๋ถ๊ดด(์ ํจ์ฌ ์๋)=์ฆ์(์ ๊บพ์ ์ ๊ธฐ๋ค๋ฆผ).
|
| 476 |
+
# '+240'์ด๋ฉด ์ถ๊ฐ๋ก 240์ ์ด ๋๋ฌด ๊ฐํ๋ฅธ ์ฐ์ํฅ(>FLAT_MAX_240)์ด๋ฉด ๋งค๋ ๊ธ์ง(์์น ํ๋ณตํ ๋๋ฆผ).
|
| 477 |
+
def chk(t):
|
| 478 |
+
if line_arr is None or np.isnan(line_arr[t]):
|
| 479 |
+
return True, ''
|
| 480 |
+
margin = (1 - stock[t] / line_arr[t]) # ์ ๋๋น ์ผ๋ง๋ ์๋(%)
|
| 481 |
+
if margin < CONFIRM_MARGIN:
|
| 482 |
+
return False, f'{line_no}์ ์ด์ง(-{margin*100:.1f}%<{CONFIRM_MARGIN*100:.0f}%)โ๋ณด๋ฅ'
|
| 483 |
+
if CONFIRM_NEEDS_FLAT == 'MARGIN+240':
|
| 484 |
+
s240 = slope_at(240, t)
|
| 485 |
+
if s240 is not None and s240 > FLAT_MAX_240:
|
| 486 |
+
return False, f'240 ๊ฐํ๋ฅธ์์น({s240*100:+.1f}%>{FLAT_MAX_240*100:.0f}%)=๋๋ฆผโ๋ณด๋ฅ'
|
| 487 |
+
return True, f'{line_no}์ -{margin*100:.1f}%(๋ถ๊ดด)'
|
| 488 |
+
return chk
|
| 489 |
+
if CONFIRM_NEEDS_FLAT == '240':
|
| 490 |
+
def chk(t):
|
| 491 |
+
s = slope_at(240, t)
|
| 492 |
+
if s is None:
|
| 493 |
+
return True, ''
|
| 494 |
+
if not (FLAT_MIN_240 < s <= FLAT_MAX_240):
|
| 495 |
+
return False, f'240๊ธฐ์ธ๊ธฐ {s*100:+.1f}%โ({FLAT_MIN_240*100:.0f},{FLAT_MAX_240*100:.0f}]โ๋ณด๋ฅ'
|
| 496 |
+
return True, f'240๊ธฐ์ธ๊ธฐ {s*100:+.1f}%'
|
| 497 |
+
return chk
|
| 498 |
+
return lambda t: (True, '') # 'OFF'
|
| 499 |
+
|
| 500 |
+
_g60 = _flat_gate(60); _g120 = _flat_gate(120)
|
| 501 |
+
|
| 502 |
+
def _confirm(t):
|
| 503 |
+
"""๋ฌด์ฅ ํ '๋งค๋ ํ์ธ' ์ ํธ. ๋ชจ๋๋ณ:
|
| 504 |
+
A4=์ดํ์ ํํ(๋๋ฆผ/์์ ) / MA60=์ข
๊ฐ<60์ (๋น ๋ฆ) / MA120=์ข
๊ฐ<120์ (์ค๊ฐ) / NONE=RS๋ง.
|
| 505 |
+
MA60/120์ CONFIRM_NEEDS_FLAT ๊ธฐ์ธ๊ธฐ ๊ฒ์ดํธ๋ ํต๊ณผํด์ผ ํจ(์ค๋ฅผ ๋ ๋งค๋ ๊ธ์ง)."""
|
| 506 |
+
if RS_CONFIRM == 'NONE':
|
| 507 |
+
return True, 'RS๋จ๋
'
|
| 508 |
+
if RS_CONFIRM == 'MA60':
|
| 509 |
+
if ma60 is None or np.isnan(ma60[t]):
|
| 510 |
+
return False, '60์ ์์'
|
| 511 |
+
if stock[t] >= ma60[t]:
|
| 512 |
+
return False, f'60์ ์(์ข
๊ฐ {stock[t]:,.0f}>{ma60[t]:,.0f})'
|
| 513 |
+
gok, gwhy = _g60(t)
|
| 514 |
+
if not gok:
|
| 515 |
+
return False, gwhy
|
| 516 |
+
return True, f'์ข
๊ฐ<60์ ({ma60[t]:,.0f}) {gwhy}'.strip()
|
| 517 |
+
if RS_CONFIRM == 'MA120':
|
| 518 |
+
if ma120 is None or np.isnan(ma120[t]):
|
| 519 |
+
return False, '120์ ์์'
|
| 520 |
+
if stock[t] >= ma120[t]:
|
| 521 |
+
return False, f'120์ ์(์ข
๊ฐ {stock[t]:,.0f}>{ma120[t]:,.0f})'
|
| 522 |
+
gok, gwhy = _g120(t)
|
| 523 |
+
if not gok:
|
| 524 |
+
return False, gwhy
|
| 525 |
+
return True, f'์ข
๊ฐ<120์ ({ma120[t]:,.0f}) {gwhy}'.strip()
|
| 526 |
+
return _gate(t) # 'A4'
|
| 527 |
+
|
| 528 |
armed = False; armed_date = None; sold = False; weak_run = 0
|
| 529 |
+
locked = False; lock_i = -1
|
| 530 |
for t in range(n):
|
| 531 |
div = (stock[t] / twpk[t] - 1) - ((index[t] / twip[t] - 1) if twip[t] else 0.0)
|
| 532 |
|
| 533 |
+
# SELL_ONCE ์ ๊ธ: ๋งค๋ ํ (1)RELOCK_LINE ํ๋ณต AND (2)์ต์๊ธฐ๊ฐ ๊ฒฝ๊ณผ ๋ ๋ค์ฌ์ผ ํ๋ฆผ
|
| 534 |
+
if locked:
|
| 535 |
+
line = {60: ma60, 120: ma120, 240: ma240}.get(RELOCK_LINE, ma240)
|
| 536 |
+
if line is None:
|
| 537 |
+
line = ma120 if ma120 is not None else ma60
|
| 538 |
+
above = (line is not None and not np.isnan(line[t]) and stock[t] > line[t])
|
| 539 |
+
enough_days = (t - lock_i) >= RELOCK_MIN_DAYS
|
| 540 |
+
if above and enough_days:
|
| 541 |
+
locked = False; armed = False; weak_run = 0; sold = False
|
| 542 |
+
if t >= start_pos:
|
| 543 |
+
_step(t, f'์ฌ๋ฌด์ฅ ๊ฐ๋ฅ({RELOCK_LINE}์ ํ๋ณต+{t-lock_i}์ผ๊ฒฝ๊ณผ=์ ์ฌ์ดํด)', div)
|
| 544 |
+
else:
|
| 545 |
+
continue # ์ ๊ฒจ์์ผ๋ฉด ์นจ๋ฌต
|
| 546 |
+
|
| 547 |
if rs_weak[t]:
|
| 548 |
weak_run += 1
|
| 549 |
else:
|
| 550 |
+
# RS๊ฐ ๋ค์ ์์ฅ๋ณด๋ค ๊ฐํด์ง -> ๋ฌด์ฅ ํด์
|
| 551 |
if armed and t >= start_pos:
|
| 552 |
_step(t, '๋ฌด์ฅ ํด์ (RS ํ๋ณต)', div)
|
| 553 |
+
armed = False; weak_run = 0
|
| 554 |
+
if not SELL_ONCE:
|
| 555 |
+
sold = False
|
| 556 |
continue
|
| 557 |
|
| 558 |
+
# RS_PERSIST์ผ ์ฐ์ ์ฝํ๋ฉด ๋ฌด์ฅ (์ด๋ฏธ ํ ์ํ๋ฉด ๋ฌด์ฅ ์ ํจ)
|
| 559 |
+
if not armed and not sold and weak_run >= RS_PERSIST:
|
| 560 |
+
# (1) ์ข
๊ฐ๊ฐ 240์ ๋ณด๋ค ๊น์ด ์๋ = ์ถ์ธ ๋ฌด๋์ง -> ๋ฌด์ฅ ๊ธ์ง
|
| 561 |
+
deep_below = False
|
| 562 |
+
if NO_ARM_BELOW_240 is not None and ma240 is not None and not np.isnan(ma240[t]):
|
| 563 |
+
deep_below = (stock[t] / ma240[t] - 1) <= NO_ARM_BELOW_240
|
| 564 |
+
# (2) ์ด๊ฒฉ(๊ณ ์ ๋๋น ๋ํญ)์ด ์ด๋ฏธ ๋๋ฌด ๊น์ = ์ตํ๋ณด๋ฃจ ์์ ์ง๋จ -> ๋ฌด์ฅ ๊ธ์ง
|
| 565 |
+
deep_div = (NO_ARM_DIV_BELOW is not None and div <= NO_ARM_DIV_BELOW)
|
| 566 |
+
if deep_below or deep_div:
|
| 567 |
+
if t >= start_pos:
|
| 568 |
+
why = (f'์ด๊ฒฉ {div*100:.0f}%โค{NO_ARM_DIV_BELOW*100:.0f}%(๊ณ ์ ๋๋น ํ์ฐธ ๋น ์ง)'
|
| 569 |
+
if deep_div else
|
| 570 |
+
f'์ข
๊ฐ 240์ {(stock[t]/ma240[t]-1)*100:.0f}%(์ถ์ธ์ดํ)')
|
| 571 |
+
_step(t, '๋ฌด์ฅ ๋ณด๋ฅ(์ตํ๋ณด๋ฃจ ๋์ ์๋)', div, why)
|
| 572 |
+
else:
|
| 573 |
+
armed = True; armed_date = dates[t]
|
| 574 |
+
rsd = (rs[t] / rs_ma[t] - 1) * 100
|
| 575 |
+
_step(t, '๋ฌด์ฅ(RS ๋ฐ๋ํฌ๋ก์ค)', div, f'RS {rsd:.1f}% < MA{RS_MA_PERIOD}')
|
| 576 |
|
| 577 |
if armed and not sold:
|
| 578 |
+
ok, why = _confirm(t)
|
| 579 |
+
# ๊ฐํ ์์น์ถ์ธ(240์ฌ) ์ค์ด๋ฉด ๋งค๋ ๋ณด๋ฅ = ์์น ํ๋ณตํ ๋๋ฆผ false alarm ๋ฐฉ์ง
|
| 580 |
+
if ok and NO_SELL_STRONG_UPTREND and ma240 is not None and in_240_run(stock, ma240, t):
|
| 581 |
+
ok = False
|
| 582 |
+
if t >= start_pos:
|
| 583 |
+
_step(t, '๋งค๋ ๋ณด๋ฅ(๊ฐํ ์์น์ถ์ธ=240์ฌ, ๋๋ฆผ)', div,
|
| 584 |
+
f'์ข
๊ฐ {stock[t]:,.0f} > 240์ +{TREND_MIN_GAP*100:.0f}%, {TREND_MIN_DAYS}์ผ์ฐ์ 240์')
|
| 585 |
if ok:
|
| 586 |
if t >= start_pos:
|
| 587 |
est = bool(ma240_est[t]) if ma240_est is not None else False
|
| 588 |
sells.append({'i': t, 'price': float(stock[t]), 'div': div,
|
| 589 |
'date': dates[t], 'trend': why,
|
| 590 |
'via': f'RS๋ฌด์ฅ({armed_date})', 'est': est})
|
| 591 |
+
_step(t, '์ ๋๋งค๋ โ
๋ฐ๋', div, f'RS๋ฌด์ฅ ํ ํ์ธ[{RS_CONFIRM}]: {why}')
|
|
|
|
| 592 |
sold = True
|
| 593 |
+
if SELL_ONCE:
|
| 594 |
+
locked = True; lock_i = t # ํ ๋ฒ ํ๋ฉด ์ ๊ธ(ํด์ ์ +๊ธฐ๊ฐ ๋ ๋ค ์ถฉ์กฑ๊น์ง)
|
| 595 |
else:
|
| 596 |
+
pass # ๋ฌด์ฅ๋์ง๋ง ํ์ธ์ ํธ ์์ง(๋๋ ์์น์ถ์ธ ๋ณด๋ฅ) -> ๋๊ธฐ
|
| 597 |
|
| 598 |
# ํ์ฌ ์ํ
|
| 599 |
last = n - 1
|
| 600 |
if not sold:
|
| 601 |
div = (stock[last] / twpk[last] - 1) - ((index[last] / twip[last] - 1) if twip[last] else 0.0)
|
| 602 |
if armed:
|
| 603 |
+
ok, why = _confirm(last)
|
| 604 |
+
note = f'ํ์ธ[{RS_CONFIRM}] ๋๊ธฐ์ค ({why})'
|
| 605 |
_step(last, '[ํ์ฌ] ๋ฌด์ฅ๋จ(๋งค๋ ๋๊ธฐ)', div, note)
|
| 606 |
else:
|
| 607 |
_step(last, '[ํ์ฌ] ๊ด๋ง (RS ์์ง ์์ฅ๋ณด๋ค ์ ์ฝํจ)', div, '')
|
|
|
|
| 715 |
else:
|
| 716 |
tf_s = "์ถ์ธํํฐ=OFF"
|
| 717 |
if ENGINE == 'RS_A4':
|
| 718 |
+
rs_confirm = {'A4': 'A-4ํํ', 'MA60': '์ข
๊ฐ<60์ ', 'MA120': '์ข
๊ฐ<120์ ',
|
| 719 |
+
'NONE': 'RS๋จ๋
'}.get(RS_CONFIRM, RS_CONFIRM)
|
| 720 |
+
print(f"์์ง=RS_A4 | RS(EMA{RS_SMOOTH})<MA{RS_MA_PERIOD}ร(1-{RS_BUFFER*100:.0f}%) "
|
| 721 |
+
f"{RS_PERSIST}์ผ์ฐ์ ๋ฌด์ฅ -> ํ์ธ[{rs_confirm}] ์ฆ์๋งค๋ | {tf_s}")
|
| 722 |
else:
|
| 723 |
div_s = f"์ด๊ฒฉ๊ธฐ์ค={DIV_THRESHOLD*100:.0f}%(๊ณ ์ )"
|
| 724 |
jmp_s = f"ํ๋ฃจ๊ธ๋ณ({DAILY_JUMP*100:.0f}%p)์ ํ"
|
|
|
|
| 816 |
else:
|
| 817 |
print(f" {tk} {market} - ๋งค๋ ์์")
|
| 818 |
|
| 819 |
+
# ---- ํ๋ฃจ ๊ธ๋ณ ์ ํ ๋ฐ๋ ๋ด์ญ (STAGE ์์ง ์ ์ฉ. RS_A4๋ ๋จ๊ณ๊ฐ๋
์์ด์ ์๋ต) ----
|
| 820 |
+
if ENGINE != 'RS_A4':
|
| 821 |
+
print("\n" + "=" * 88)
|
| 822 |
+
print(f"[ํ๋ฃจ ๊ธ๋ณ ์ ํ ๋ฐ๋ ๋ด์ญ] (์ ์ผ ์ด๊ฒฉ ๋๋น {DAILY_JUMP*100:.0f}%p+ ๊ธ๋ฝ -> ๋๊ธฐ๋จ๊ณ ๊ฑด๋๋)")
|
| 823 |
+
print("=" * 88)
|
| 824 |
+
if not all_jumps:
|
| 825 |
+
print(" ๋ฐ๋ ์์")
|
| 826 |
+
else:
|
| 827 |
+
n_skip = sum(1 for _, _, j in all_jumps if j['skip'])
|
| 828 |
+
print(f" ์ด {len(all_jumps)}ํ ๋ฐ๋ (์ด ์ค '๋๊ธฐ ๊ฑด๋๋(SKIP)' {n_skip}ํ)\n")
|
| 829 |
+
print(f" {'์ข
๋ชฉ':<8}{'์์ฅ':<7}{'๋ ์ง':<12}{'ํ๋ฃจ๋ํญ':>8}{'์ด๊ฒฉ':>8} ๋จ๊ณ์ ํ")
|
| 830 |
+
print(" " + "-" * 70)
|
| 831 |
+
for tk, market, j in sorted(all_jumps, key=lambda z: z[2]['date']):
|
| 832 |
+
mark = ' โ
๊ฑด๋๋' if j['skip'] else ''
|
| 833 |
+
print(f" {tk:<8}{market:<7}{j['date']:<12}"
|
| 834 |
+
f"{j['drop']*100:>7.1f}%{j['div']*100:>7.1f}% "
|
| 835 |
+
f"{j['from']} -> {j['to']}{mark}")
|
| 836 |
|
| 837 |
|
| 838 |
if __name__ == '__main__':
|