Spaces:
Running
Running
Update confirm_sell_backtest.py
Browse files- confirm_sell_backtest.py +70 -44
confirm_sell_backtest.py
CHANGED
|
@@ -45,9 +45,14 @@ TICKERS = {
|
|
| 45 |
# =============================================
|
| 46 |
# ์ค์
|
| 47 |
# =============================================
|
| 48 |
-
DIV_THRESHOLD = -0.10 # ์ด๊ฒฉ ๊ธฐ์ค
|
| 49 |
MIN_DEEPEN = 0.020 # ๋ค์ ๋จ๊ณ๋ก ๊ฐ๋ ค๋ฉด ์ง์ ๋จ๊ณ๋ณด๋ค ์ต์ ์ด๋งํผ(%p) ๋ ๊น์ด์ผ (๋
ธ์ด์ฆ ๋ฐฉ์ง)
|
| 50 |
-
DAILY_JUMP = 0.10 # ํ๋ฃจ๋ง์ ์ด๊ฒฉ์ด ์ ์ผ
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 51 |
PEAK_WINDOW = 252 # ๊ณ ์ ๊ธฐ์ค = ์ต๊ทผ N๊ฑฐ๋์ผ(252=1๋
) ๋ด ์ต๊ณ ์ (์ค๋๋ ๊ณ ์ ์ ์ ๋ฌถ์)
|
| 52 |
# CONFIRM_WINDOW ์ ๊ฑฐ๋จ: 1์ฐจ->2์ฐจ ์ฌ์ด ์ผ์ ์ ํ ์์ (๋ฉฐ์น ์ด ๊ฑธ๋ฆฌ๋ ์ฐ์ ํ์ฉ)
|
| 53 |
|
|
@@ -196,7 +201,7 @@ def trend_ok(t, stock, ma240, ma60=None, ma120=None, flat_slopes=None):
|
|
| 196 |
|
| 197 |
def find_confirmed_sells(stock, index, dates, start_pos, ma60=None, ma240=None,
|
| 198 |
low=None, bbl=None, ma240_est=None, ma120=None):
|
| 199 |
-
"""ํ์ ๋งค๋
|
| 200 |
n = len(stock)
|
| 201 |
twpk, twip = _trailing_peaks(stock, index, PEAK_WINDOW)
|
| 202 |
|
|
@@ -207,6 +212,14 @@ def find_confirmed_sells(stock, index, dates, start_pos, ma60=None, ma240=None,
|
|
| 207 |
if arr is not None:
|
| 208 |
flat_slopes[ln] = _smoothed_slope(arr, FLAT_SLOPE_DAYS, FLAT_SMOOTH)
|
| 209 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 210 |
def _gate(t):
|
| 211 |
ok, why = (True, '')
|
| 212 |
if ma240 is not None:
|
|
@@ -252,7 +265,7 @@ def find_confirmed_sells(stock, index, dates, start_pos, ma60=None, ma240=None,
|
|
| 252 |
|
| 253 |
if div > DIV_THRESHOLD:
|
| 254 |
if stage != 0 and t >= start_pos:
|
| 255 |
-
_step(t, '๋ฆฌ์
(์ด๊ฒฉ
|
| 256 |
stage = 0; ref_div = None; first_i = None; sold = False
|
| 257 |
prev_div = div
|
| 258 |
continue
|
|
@@ -261,66 +274,77 @@ def find_confirmed_sells(stock, index, dates, start_pos, ma60=None, ma240=None,
|
|
| 261 |
continue
|
| 262 |
|
| 263 |
crash = (prev_div is not None) and ((div - prev_div) <= -DAILY_JUMP)
|
| 264 |
-
cnote = f'ํ๋ฃจ๊ธ๋ณ {(div-prev_div)*100:.1f}%p' if crash else ''
|
| 265 |
|
| 266 |
def _try_sell(note, via):
|
| 267 |
"""๋งค๋ ์๋. ๋ฐ๋ํ๋ฉด True(+๋ฐ๋๋ก๊ทธ), ์ฐจ๋จ๋๋ฉด False(+์ฐจ๋จ๋ก๊ทธ). ๋๊ธฐ ์ํจ."""
|
| 268 |
fired, why = _sell(t, st, div, via)
|
| 269 |
if fired:
|
| 270 |
-
_step(t, '
|
| 271 |
return True
|
| 272 |
-
_step(t, f'
|
| 273 |
return False
|
| 274 |
|
|
|
|
|
|
|
|
|
|
| 275 |
if stage == 0:
|
| 276 |
if crash:
|
| 277 |
-
|
| 278 |
-
|
| 279 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 280 |
else:
|
| 281 |
-
stage = 1; ref_div = div
|
| 282 |
-
|
| 283 |
-
|
| 284 |
-
|
| 285 |
-
|
| 286 |
-
|
| 287 |
-
_step(t, '1์ฐจ', div, cnote)
|
| 288 |
-
elif div <= ref_div - MIN_DEEPEN:
|
| 289 |
-
stage = 2; ref_div = div; first_i = t
|
| 290 |
-
_step(t, '1์ฐจ', div, f'์ง์ ๆฏ {(div-ref_div)*100:.1f}%p')
|
| 291 |
-
elif stage == 2:
|
| 292 |
-
if crash:
|
| 293 |
-
_log_jump(t, 2, 4, div, prev_div, st)
|
| 294 |
-
if _try_sell(cnote + ' (2์ฐจflagON ๊ฑด๋๋)', '๊ธ๋ณ์ ํ'):
|
| 295 |
-
sold = True
|
| 296 |
else:
|
| 297 |
-
|
| 298 |
-
|
| 299 |
-
|
| 300 |
-
_step(t, '2์ฐจ flag ON', div, f'์ง์ ๆฏ {(div-ref_div)*100:.1f}%p')
|
| 301 |
-
elif stage == 3:
|
| 302 |
if crash:
|
| 303 |
-
|
| 304 |
-
if _try_sell(cnote, '๊ธ๋ณ์ ํ'):
|
| 305 |
-
sold = True
|
| 306 |
-
else:
|
| 307 |
-
ref_div = div # ์ฐจ๋จ -> ๊ธฐ์ค๋ง ๊ฐฑ์ , ๋ ๊น์ด์ง๋ฉด ๋ค์ ํ๋จ
|
| 308 |
elif div <= ref_div - MIN_DEEPEN:
|
| 309 |
-
|
| 310 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 311 |
else:
|
| 312 |
-
|
|
|
|
| 313 |
prev_div = div
|
| 314 |
|
| 315 |
# ๊ด์ฐฐ ์ข
๋ฃ ์์ , ์์ง ๋งค๋ ์ ๋ฌ๊ณ ๋จ๊ณ ๋๊ธฐ ์ค์ด๋ฉด ํ์ฌ ์ํ ๊ธฐ๋ก
|
| 316 |
-
if not sold and
|
| 317 |
last = n - 1
|
| 318 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 319 |
cur = float(stock[last] / twpk[last] - 1) - ((float(index[last] / twip[last] - 1)) if twip[last] else 0.0)
|
| 320 |
need = cur - (ref_div - MIN_DEEPEN) # >0 ์ด๋ฉด ์ด๋งํผ ๋ ๊น์ด์ ธ์ผ ๋ค์ ๋จ๊ณ
|
| 321 |
note = (f'๋ค์ ๋จ๊ณ๊น์ง {need*100:.1f}%p ๋ ํ๋ฝ ํ์' if need > 0
|
| 322 |
else '์กฐ๊ฑด ์ถฉ์กฑ์ํ(๋ค์๋ด ํ์ธ)')
|
| 323 |
-
_step(last, f'[ํ์ฌ] {
|
| 324 |
return sells, jumps, steps
|
| 325 |
|
| 326 |
|
|
@@ -430,8 +454,10 @@ def main():
|
|
| 430 |
f"240{_b(FLAT_MIN_240,FLAT_MAX_240)}]")
|
| 431 |
else:
|
| 432 |
tf_s = "์ถ์ธํํฐ=OFF"
|
| 433 |
-
|
| 434 |
-
|
|
|
|
|
|
|
| 435 |
print(f"์ฑ์ : ๊ด์ฐฐ {LOOK_AHEAD}์ผ | E์จ=240์ดํ(์กฐ๊ธฐ๊ฒฝ๋ณด) | P์จ=๋งค๋๊ฐ๋๋น {PROTECT_DROP*100:.0f}% ์ถ๊ฐํ๋ฝ ํํผ")
|
| 436 |
print("=" * 88)
|
| 437 |
|
|
@@ -542,4 +568,4 @@ def main():
|
|
| 542 |
|
| 543 |
|
| 544 |
if __name__ == '__main__':
|
| 545 |
-
main()
|
|
|
|
| 45 |
# =============================================
|
| 46 |
# ์ค์
|
| 47 |
# =============================================
|
| 48 |
+
DIV_THRESHOLD = -0.10 # ์ด๊ฒฉ ๊ธฐ์ค(๊ณ ์ ). ์ด๊ฒฉ์ด ์ด๋ณด๋ค ๊น์ด์ง๋ฉด flag ON ์์.
|
| 49 |
MIN_DEEPEN = 0.020 # ๋ค์ ๋จ๊ณ๋ก ๊ฐ๋ ค๋ฉด ์ง์ ๋จ๊ณ๋ณด๋ค ์ต์ ์ด๋งํผ(%p) ๋ ๊น์ด์ผ (๋
ธ์ด์ฆ ๋ฐฉ์ง)
|
| 50 |
+
DAILY_JUMP = 0.10 # ํ๋ฃจ๋ง์ ์ด๊ฒฉ์ด ์ ์ผๆฏ ์ด๋งํผ(%p)+ ๊ธ๋ฝํ๋ฉด '๋๊ธฐ' ๊ฑด๋๋ฐ๊ณ ์ ํ
|
| 51 |
+
|
| 52 |
+
# --- ๋จ๊ณ ์ ์์ก์ด: flag ON ํ '๋ช ๋ฒ ๋ ๊น์ด์ ธ์ผ' ์ ๋๋งค๋๊ฐ ๋ฐ๋ํ๋ ---
|
| 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 |
|
|
|
|
| 201 |
|
| 202 |
def find_confirmed_sells(stock, index, dates, start_pos, ma60=None, ma240=None,
|
| 203 |
low=None, bbl=None, ma240_est=None, ma120=None):
|
| 204 |
+
"""ํ์ ๋งค๋ ์ฐพ๊ธฐ โ ๋จ๊ณ๋์ (CONFIRM_STAGES๋จ๊ณ)+๊ธ๋ณ์ ํ + ์ถ์ธํํฐ(A-4)."""
|
| 205 |
n = len(stock)
|
| 206 |
twpk, twip = _trailing_peaks(stock, index, PEAK_WINDOW)
|
| 207 |
|
|
|
|
| 212 |
if arr is not None:
|
| 213 |
flat_slopes[ln] = _smoothed_slope(arr, FLAT_SLOPE_DAYS, FLAT_SMOOTH)
|
| 214 |
|
| 215 |
+
SELL_STAGE = max(1, int(CONFIRM_STAGES)) + 1 # ์ด ๋จ๊ณ์ ๋๋ฌํ๋ฉด ์ ๋๋งค๋
|
| 216 |
+
|
| 217 |
+
def _sname(stg):
|
| 218 |
+
"""๋จ๊ณ ์ด๋ฆ. ๊ธฐ๋ณธ(CONFIRM_STAGES=3)์ด๋ฉด ์น์ํ 1์ฐจ/2์ฐจ ์ด๋ฆ, ์๋๋ฉด N๋จ๊ณ."""
|
| 219 |
+
if CONFIRM_STAGES == 3:
|
| 220 |
+
return {1: 'flag ON', 2: '1์ฐจ', 3: '2์ฐจ flag ON'}.get(stg, f'{stg}๋จ๊ณ')
|
| 221 |
+
return 'flag ON' if stg == 1 else f'{stg}๋จ๊ณ'
|
| 222 |
+
|
| 223 |
def _gate(t):
|
| 224 |
ok, why = (True, '')
|
| 225 |
if ma240 is not None:
|
|
|
|
| 265 |
|
| 266 |
if div > DIV_THRESHOLD:
|
| 267 |
if stage != 0 and t >= start_pos:
|
| 268 |
+
_step(t, f'๋ฆฌ์
(์ด๊ฒฉ {DIV_THRESHOLD*100:.0f}%์ ํ๋ณต)', div)
|
| 269 |
stage = 0; ref_div = None; first_i = None; sold = False
|
| 270 |
prev_div = div
|
| 271 |
continue
|
|
|
|
| 274 |
continue
|
| 275 |
|
| 276 |
crash = (prev_div is not None) and ((div - prev_div) <= -DAILY_JUMP)
|
| 277 |
+
cnote = f'ํ๋ฃจ๊ธ๋ณ {(div-prev_div)*100:.1f}%p (์ ํ๊ธฐ์ค {DAILY_JUMP*100:.0f}%p)' if crash else ''
|
| 278 |
|
| 279 |
def _try_sell(note, via):
|
| 280 |
"""๋งค๋ ์๋. ๋ฐ๋ํ๋ฉด True(+๋ฐ๋๋ก๊ทธ), ์ฐจ๋จ๋๋ฉด False(+์ฐจ๋จ๋ก๊ทธ). ๋๊ธฐ ์ํจ."""
|
| 281 |
fired, why = _sell(t, st, div, via)
|
| 282 |
if fired:
|
| 283 |
+
_step(t, '์ ๋๋งค๋ โ
๋ฐ๋', div, note + ' ' + _bd)
|
| 284 |
return True
|
| 285 |
+
_step(t, f'๋งค๋์กฐ๊ฑด ์ถฉ์กฑํ์ผ๋ ์ฐจ๋จ({why}) โ ์ด๋ฒ ์ ํธ ๋ฌด์', div, note)
|
| 286 |
return False
|
| 287 |
|
| 288 |
+
# --- ์ผ๋ฐํ๋ ๋จ๊ณ ๋จธ์ ---
|
| 289 |
+
# ๋ฌด์ฅ(stage>=1) ํ ๊น์ด์ง ๋๋ง๋ค stage+1 (๊ธ๋ณ์ด๋ฉด +2๋ก ํ ๋จ๊ณ ๊ฑด๋๋).
|
| 290 |
+
# stage ๊ฐ SELL_STAGE ์ ๋๋ฌํ๋ฉด ์ ๋๋งค๋.
|
| 291 |
if stage == 0:
|
| 292 |
if crash:
|
| 293 |
+
nx = min(2, SELL_STAGE)
|
| 294 |
+
_log_jump(t, 0, nx, div, prev_div, st)
|
| 295 |
+
ref_div = div; first_i = t
|
| 296 |
+
if nx >= SELL_STAGE:
|
| 297 |
+
if _try_sell(cnote + ' (๋จ๊ณ ๊ฑด๋๋)', '๊ธ๋ณ์ ํ'):
|
| 298 |
+
sold = True
|
| 299 |
+
else:
|
| 300 |
+
stage = SELL_STAGE - 1 # ์ฐจ๋จ -> ๋งค๋์ง์ ๋จ๊ณ๋ก park
|
| 301 |
+
else:
|
| 302 |
+
stage = nx
|
| 303 |
+
_step(t, f'{_sname(nx)}(flag ๊ฑด๋๋)', div, cnote)
|
| 304 |
else:
|
| 305 |
+
stage = 1; ref_div = div; first_i = t
|
| 306 |
+
if stage >= SELL_STAGE: # CONFIRM_STAGES=0 ๊ฐ์ ๊ทน๋จ ์ค์
|
| 307 |
+
if _try_sell('flag์ฆ์', 'flag'):
|
| 308 |
+
sold = True
|
| 309 |
+
else:
|
| 310 |
+
stage = SELL_STAGE - 1
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 311 |
else:
|
| 312 |
+
_step(t, _sname(1), div, f'๊ธฐ์ค {DIV_THRESHOLD*100:.0f}%')
|
| 313 |
+
else:
|
| 314 |
+
adv = 0
|
|
|
|
|
|
|
| 315 |
if crash:
|
| 316 |
+
adv = 2; note = cnote
|
|
|
|
|
|
|
|
|
|
|
|
|
| 317 |
elif div <= ref_div - MIN_DEEPEN:
|
| 318 |
+
adv = 1; note = f'์ง์ ๆฏ {(div-ref_div)*100:.1f}%p'
|
| 319 |
+
if adv:
|
| 320 |
+
nx = min(stage + adv, SELL_STAGE)
|
| 321 |
+
ref_div = div
|
| 322 |
+
if nx >= SELL_STAGE:
|
| 323 |
+
if crash:
|
| 324 |
+
_log_jump(t, stage, SELL_STAGE, div, prev_div, st)
|
| 325 |
+
if _try_sell(note, '๊ธ๋ณ์ ํ' if crash else '๋จ๊ณ๋์ '):
|
| 326 |
+
sold = True
|
| 327 |
+
else:
|
| 328 |
+
stage = SELL_STAGE - 1 # ์ฐจ๋จ -> ๋งค๋์ง์ ๋จ๊ณ park, ๋ ๊น์ด์ง๋ฉด ์ฌ์๋
|
| 329 |
else:
|
| 330 |
+
stage = nx
|
| 331 |
+
_step(t, _sname(nx), div, note)
|
| 332 |
prev_div = div
|
| 333 |
|
| 334 |
# ๊ด์ฐฐ ์ข
๋ฃ ์์ , ์์ง ๋งค๋ ์ ๋ฌ๊ณ ๋จ๊ณ ๋๊ธฐ ์ค์ด๋ฉด ํ์ฌ ์ํ ๊ธฐ๋ก
|
| 335 |
+
if not sold and 1 <= stage < SELL_STAGE and ref_div is not None:
|
| 336 |
last = n - 1
|
| 337 |
+
if CONFIRM_STAGES == 3:
|
| 338 |
+
nm = {1: '1์ฐจ flag', 2: '1์ฐจ (๋ค์: 2์ฐจ flag)',
|
| 339 |
+
3: '2์ฐจ flag (์ ๋๋งค๋ ์๋ฐ!)'}.get(stage, f'{stage}๋จ๊ณ')
|
| 340 |
+
else:
|
| 341 |
+
tail = ' (๋ค์: ์ ๋๋งค๋!)' if stage == SELL_STAGE - 1 else ''
|
| 342 |
+
nm = f'{stage}๋จ๊ณ / ๋งค๋๊น์ง {SELL_STAGE}๋จ๊ณ{tail}'
|
| 343 |
cur = float(stock[last] / twpk[last] - 1) - ((float(index[last] / twip[last] - 1)) if twip[last] else 0.0)
|
| 344 |
need = cur - (ref_div - MIN_DEEPEN) # >0 ์ด๋ฉด ์ด๋งํผ ๋ ๊น์ด์ ธ์ผ ๋ค์ ๋จ๊ณ
|
| 345 |
note = (f'๋ค์ ๋จ๊ณ๊น์ง {need*100:.1f}%p ๋ ํ๋ฝ ํ์' if need > 0
|
| 346 |
else '์กฐ๊ฑด ์ถฉ์กฑ์ํ(๋ค์๋ด ํ์ธ)')
|
| 347 |
+
_step(last, f'[ํ์ฌ] {nm}', cur, note)
|
| 348 |
return sells, jumps, steps
|
| 349 |
|
| 350 |
|
|
|
|
| 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 |
|
|
|
|
| 568 |
|
| 569 |
|
| 570 |
if __name__ == '__main__':
|
| 571 |
+
main()
|