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

Update confirm_sell_backtest.py

Browse files
Files changed (1) hide show
  1. 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 # ํ•˜๋ฃจ๋งŒ์— ์ด๊ฒฉ์ด ์ „์ผ ๋Œ€๋น„ ์ด๋งŒํผ(%p)+ ๊ธ‰๋ฝํ•˜๋ฉด '๋Œ€๊ธฐ' ๊ฑด๋„ˆ๋›ฐ๊ณ  ๋ฐ”๋กœ ํ™•์ • ์ ํ”„
 
 
 
 
 
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
- """ํ™•์ •๋งค๋„(2์ฐจ) ์ฐพ๊ธฐ โ€” ๋‹จ๊ณ„๋ˆ„์ +๊ธ‰๋ณ€์ ํ”„ + ์ถ”์„ธํ•„ํ„ฐ(A-4)."""
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, '๋ฆฌ์…‹(์ด๊ฒฉ -10%์œ„ ํšŒ๋ณต)', div)
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, '2์ฐจ ์ „๋Ÿ‰๋งค๋„ โ˜…๋ฐœ๋™', div, note + ' ' + _bd)
271
  return True
272
- _step(t, f'2์ฐจ ๋งค๋„์กฐ๊ฑด ์ถฉ์กฑํ–ˆ์œผ๋‚˜ ์ฐจ๋‹จ({why}) โ€” ์ด๋ฒˆ ์‹ ํ˜ธ ๋ฌด์‹œ', div, note)
273
  return False
274
 
 
 
 
275
  if stage == 0:
276
  if crash:
277
- _log_jump(t, 0, 2, div, prev_div, st)
278
- stage = 2; ref_div = div; first_i = t
279
- _step(t, '1์ฐจ(flagON ๊ฑด๋„ˆ๋œ€)', div, cnote)
 
 
 
 
 
 
 
 
280
  else:
281
- stage = 1; ref_div = div
282
- _step(t, 'flag ON', div)
283
- elif stage == 1:
284
- if crash:
285
- _log_jump(t, 1, 2, div, prev_div, st)
286
- stage = 2; ref_div = div; first_i = t
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
- stage = 3; ref_div = div # ์ฐจ๋‹จ -> 2์ฐจflagON ๋‹จ๊ณ„๋กœ๋งŒ ์˜ฌ๋ ค๋‘ (๋Œ€๊ธฐX)
298
- elif div <= ref_div - MIN_DEEPEN:
299
- stage = 3; ref_div = div
300
- _step(t, '2์ฐจ flag ON', div, f'์ง์ „ๆฏ” {(div-ref_div)*100:.1f}%p')
301
- elif stage == 3:
302
  if crash:
303
- _log_jump(t, 3, 4, div, prev_div, st)
304
- if _try_sell(cnote, '๊ธ‰๋ณ€์ ํ”„'):
305
- sold = True
306
- else:
307
- ref_div = div # ์ฐจ๋‹จ -> ๊ธฐ์ค€๋งŒ ๊ฐฑ์‹ , ๋” ๊นŠ์–ด์ง€๋ฉด ๋‹ค์‹œ ํŒ๋‹จ
308
  elif div <= ref_div - MIN_DEEPEN:
309
- if _try_sell(f'์ง์ „ๆฏ” {(div-ref_div)*100:.1f}%p', '๋‹จ๊ณ„๋ˆ„์ '):
310
- sold = True
 
 
 
 
 
 
 
 
 
311
  else:
312
- ref_div = div # ์ฐจ๋‹จ -> ๊ธฐ์ค€ ๊ฐฑ์‹ , ๋‹ค์Œ์— ๋˜ 2.5%p ๋” ๊นŠ์–ด์ง€๋ฉด ์žฌ์‹œ๋„
 
313
  prev_div = div
314
 
315
  # ๊ด€์ฐฐ ์ข…๋ฃŒ ์‹œ์ , ์•„์ง ๋งค๋„ ์•ˆ ๋‚ฌ๊ณ  ๋‹จ๊ณ„ ๋Œ€๊ธฐ ์ค‘์ด๋ฉด ํ˜„์žฌ ์ƒํƒœ ๊ธฐ๋ก
316
- if not sold and stage in (1, 2, 3) and ref_div is not None:
317
  last = n - 1
318
- sname = {1: 'flag ON(๋Œ€๊ธฐ)', 2: '1์ฐจ(2์ฐจflagON ๋Œ€๊ธฐ)', 3: '2์ฐจ flag ON(์ „๋Ÿ‰๋งค๋„ ๋Œ€๊ธฐ)'}[stage]
 
 
 
 
 
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'[ํ˜„์žฌ] {sname}', cur, note)
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
- print(f"๊ทœ์น™: ๊ณ ์ =์ตœ๊ทผ{PEAK_WINDOW}์ผ๋‚ด์ตœ๊ณ  | ๋‹จ๊ณ„๋ˆ„์ ({MIN_DEEPEN*100:.1f}%p+) | "
434
- f"ํ•˜๋ฃจ๊ธ‰๋ณ€({DAILY_JUMP*100:.0f}%p)์ ํ”„ | {tf_s}")
 
 
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()