Spaces:
Running
Running
johnkim commited on
Commit ·
4ba615c
1
Parent(s): c2f6566
현재 상태 문구 수정
Browse files- README.md +2 -2
- app.py +3 -7
- buy_engine_dipfix.py +24 -28
README.md
CHANGED
|
@@ -1,5 +1,5 @@
|
|
| 1 |
---
|
| 2 |
-
title:
|
| 3 |
emoji: 📉
|
| 4 |
colorFrom: red
|
| 5 |
colorTo: gray
|
|
@@ -8,7 +8,7 @@ app_file: app.py
|
|
| 8 |
pinned: false
|
| 9 |
---
|
| 10 |
|
| 11 |
-
#
|
| 12 |
|
| 13 |
보유종목 코드를 넣으면 최근 매도신호 여부를 알려줍니다.
|
| 14 |
|
|
|
|
| 1 |
---
|
| 2 |
+
title: WTW Outlook
|
| 3 |
emoji: 📉
|
| 4 |
colorFrom: red
|
| 5 |
colorTo: gray
|
|
|
|
| 8 |
pinned: false
|
| 9 |
---
|
| 10 |
|
| 11 |
+
# WTW Outlook
|
| 12 |
|
| 13 |
보유종목 코드를 넣으면 최근 매도신호 여부를 알려줍니다.
|
| 14 |
|
app.py
CHANGED
|
@@ -436,7 +436,6 @@ def run_status(text):
|
|
| 436 |
be.run(df, "1day")
|
| 437 |
status = getattr(be, "LAST_STATUS", "") or "(상태 없음)"
|
| 438 |
kind = getattr(be, "LAST_STATUS_KIND", "wait")
|
| 439 |
-
short = getattr(be, "LAST_STATUS_SHORT", "") or "현상태"
|
| 440 |
except Exception as e:
|
| 441 |
out.append(f"- {_label(code)}: 분석 실패 ({e})"); continue
|
| 442 |
last_date = str(df.index[-1])[:10]
|
|
@@ -444,23 +443,20 @@ def run_status(text):
|
|
| 444 |
# 색상 일관성(최후보루와 동일): 🟢초록=좋음(매수 국면), ⚠️주황=주의(무너지는 중)
|
| 445 |
if kind == "buy":
|
| 446 |
line = f'<span style="color:#16a34a;font-weight:700">🟢 {status}</span>'
|
| 447 |
-
lbl = f'<span style="color:#16a34a;font-weight:700">🟢 {short}</span>'
|
| 448 |
elif kind == "danger":
|
| 449 |
line = f'<span style="color:#ea580c;font-weight:700">⚠️ {status}</span>'
|
| 450 |
-
lbl = f'<span style="color:#ea580c;font-weight:700">⚠️ {short}</span>'
|
| 451 |
else:
|
| 452 |
line = status
|
| 453 |
-
lbl = short
|
| 454 |
out.append(f"### 📈 {_label(code)} ({market_of(code)})\n"
|
| 455 |
-
f"- **[일봉
|
| 456 |
f"- 기준: {last_date} 종가 {last_px:,.0f}")
|
| 457 |
return "\n\n".join(out) if out else "결과 없음"
|
| 458 |
|
| 459 |
|
| 460 |
# UI (탭 순서: 최후보루 → 볼린저 → 삼성·ETF(RS) → 지금 상태)
|
| 461 |
# ====================================================================
|
| 462 |
-
with gr.Blocks(title="
|
| 463 |
-
gr.Markdown("# 📊
|
| 464 |
|
| 465 |
with gr.Tab("전량매도 최후보루"):
|
| 466 |
gr.Markdown("보유종목 **코드 또는 종목명**을 넣으면 매도신호/현재단계를 알려줘. (시장 자동판별, 여러 종목 가능)")
|
|
|
|
| 436 |
be.run(df, "1day")
|
| 437 |
status = getattr(be, "LAST_STATUS", "") or "(상태 없음)"
|
| 438 |
kind = getattr(be, "LAST_STATUS_KIND", "wait")
|
|
|
|
| 439 |
except Exception as e:
|
| 440 |
out.append(f"- {_label(code)}: 분석 실패 ({e})"); continue
|
| 441 |
last_date = str(df.index[-1])[:10]
|
|
|
|
| 443 |
# 색상 일관성(최후보루와 동일): 🟢초록=좋음(매수 국면), ⚠️주황=주의(무너지는 중)
|
| 444 |
if kind == "buy":
|
| 445 |
line = f'<span style="color:#16a34a;font-weight:700">🟢 {status}</span>'
|
|
|
|
| 446 |
elif kind == "danger":
|
| 447 |
line = f'<span style="color:#ea580c;font-weight:700">⚠️ {status}</span>'
|
|
|
|
| 448 |
else:
|
| 449 |
line = status
|
|
|
|
| 450 |
out.append(f"### 📈 {_label(code)} ({market_of(code)})\n"
|
| 451 |
+
f"- **[일봉]** {line}\n"
|
| 452 |
f"- 기준: {last_date} 종가 {last_px:,.0f}")
|
| 453 |
return "\n\n".join(out) if out else "결과 없음"
|
| 454 |
|
| 455 |
|
| 456 |
# UI (탭 순서: 최후보루 → 볼린저 → 삼성·ETF(RS) → 지금 상태)
|
| 457 |
# ====================================================================
|
| 458 |
+
with gr.Blocks(title="WTW Outlook") as demo:
|
| 459 |
+
gr.Markdown("# 📊 WTW Outlook")
|
| 460 |
|
| 461 |
with gr.Tab("전량매도 최후보루"):
|
| 462 |
gr.Markdown("보유종목 **코드 또는 종목명**을 넣으면 매도신호/현재단계를 알려줘. (시장 자동판별, 여러 종목 가능)")
|
buy_engine_dipfix.py
CHANGED
|
@@ -198,6 +198,7 @@ def _daily_peaks(df):
|
|
| 198 |
LAST_STATUS = '' # be.run 후 '지금 상태' 한 줄 요약 (full_debug/app이 읽음)
|
| 199 |
LAST_STATUS_KIND = 'wait' # 상태 종류(색칠용): buy/danger/dip/done/wait
|
| 200 |
LAST_STATUS_SHORT = '' # 짧은 상태명(라벨용): '산봉우리 그리는 중' 등
|
|
|
|
| 201 |
|
| 202 |
|
| 203 |
def run(df, tf='5min', sf=None, sell_dates=None, vcp_wins=None, block_ranges=None):
|
|
@@ -328,7 +329,7 @@ def run(df, tf='5min', sf=None, sell_dates=None, vcp_wins=None, block_ranges=Non
|
|
| 328 |
vlife=None; vseg_i=len(buys); vbreak_dt=None
|
| 329 |
mtn_s60 = m60; mtn_sdt = d
|
| 330 |
life = min(bl, life if life else bl)
|
| 331 |
-
phase='PEAK'; peak_gap=gap; peak_m60=m60
|
| 332 |
endlow_gap=0.0; endlow_ma60=HI; endlow_px=HI
|
| 333 |
hold=False; wave=0; armed=False; b240={}; flag240up=False
|
| 334 |
daily_open=False; pend=[]; up_peak=0.0; up_days=0
|
|
@@ -354,7 +355,7 @@ def run(df, tf='5min', sf=None, sell_dates=None, vcp_wins=None, block_ranges=Non
|
|
| 354 |
base_bbmin=HI # 새 동산 시작 → 베이스 추적 리셋
|
| 355 |
mtn_s60=start_ma60; mtn_sdt=start_dt # 이 동산의 시작점 고정
|
| 356 |
life_broken=False
|
| 357 |
-
phase='PEAK'; peak_gap=gap; peak_m60=m60
|
| 358 |
endlow_gap=0.0; endlow_ma60=HI; endlow_px=HI
|
| 359 |
ev.append((d,'산봉우리시작',f'동산 시작점 {str(mtn_sdt)[:10]} (60선 {mtn_s60:,.0f}) / 생명선 {life:,.0f}'))
|
| 360 |
|
|
@@ -393,6 +394,7 @@ def run(df, tf='5min', sf=None, sell_dates=None, vcp_wins=None, block_ranges=Non
|
|
| 393 |
life = min(endlow_bb60, endlow_bbpx)*(1-LIFELINE_MARGIN)
|
| 394 |
life_broken=False
|
| 395 |
mtn_count=1 # ★ 새 시퀀스의 첫 동산 → 위아래 매수 시작
|
|
|
|
| 396 |
wave_fresh=True # 동산 완성 직후 복귀 → 모자 체크 대상
|
| 397 |
one_wave=False # 새 동산 → 1·2번째 다 매수
|
| 398 |
wave_confirmed=False; conf_logged=False; touch_logged=False; cross_up_dt=None; wave_hat=0.0 # 복귀확인 리셋
|
|
@@ -624,7 +626,7 @@ def run(df, tf='5min', sf=None, sell_dates=None, vcp_wins=None, block_ranges=Non
|
|
| 624 |
f'깊이는 {dip_gap*100:.1f}%로 얕아도 이렇게 오래 끌면 눌림 아니라 무너짐')
|
| 625 |
ev.append((d,_tag0,
|
| 626 |
f'속았음 → 처음부터 다시 — {_rsn0} / 이번 봉우리는 직전 산보다 {(_pg0*100 if _pg0 is not None else 0):+.1f}%({_why0}) / 240선 복귀 안 기다리고 위아래 접음 / 새 시작점 {str(dip_dt)[:10]}(60선 {dip_ma60:,.0f}) / 새 생명선 {life:,.0f}'))
|
| 627 |
-
phase='PEAK'; peak_gap=gap; peak_m60=m60
|
| 628 |
endlow_gap=0.0; endlow_ma60=HI; endlow_px=HI
|
| 629 |
hold=False; wave=0; armed=False; b240={}; flag240up=False
|
| 630 |
daily_open=False; pend=[]; up_peak=0.0; up_days=0
|
|
@@ -690,7 +692,7 @@ def run(df, tf='5min', sf=None, sell_dates=None, vcp_wins=None, block_ranges=Non
|
|
| 690 |
life = min(dip_bb60, dip_bbpx)*(1-LIFELINE_MARGIN)
|
| 691 |
ev.append((d,'깊은눌림→새동산(재베이스)',
|
| 692 |
f'한 바퀴 다 돌고 무너짐 → 처음부터 다시 — 봉우리가 직전 산보다 +{_pg*100:.1f}% 크게 올랐다가(기준 +{DOUBLE_MTN_GAP*100:.0f}% 넘음) 60선이 240선 밑으로 {dip_gap*100:.1f}% 깊이 빠짐(기준 -{emin*100:.0f}% 이하) / 새 시작점 {str(dip_dt)[:10]}(60선 {dip_ma60:,.0f}) / 새 생명선 {life:,.0f}'))
|
| 693 |
-
phase='PEAK'; peak_gap=gap; peak_m60=m60
|
| 694 |
endlow_gap=0.0; endlow_ma60=HI; endlow_px=HI
|
| 695 |
hold=False; wave=0; armed=False; b240={}; flag240up=False
|
| 696 |
daily_open=False; pend=[]; up_peak=0.0; up_days=0
|
|
@@ -708,7 +710,7 @@ def run(df, tf='5min', sf=None, sell_dates=None, vcp_wins=None, block_ranges=Non
|
|
| 708 |
else ('끝지점 낮아짐' if not _end_ok else '피크데이터 없음'))
|
| 709 |
ev.append((d,'속음→재베이스(깊은붕괴)',
|
| 710 |
f'속았음 → 처음부터 다시 — 60선이 240선 밑으로 {dip_gap*100:.1f}% 깊이 빠짐(기준 -{REBASE_DEEP_PCT*100:.0f}% 이하) + 봉우리가 직전 산보다 {(_pg*100 if _pg is not None else 0):+.1f}%({_whyR}). 위아래 아님 / 새 시작점 {str(dip_dt)[:10]}(60선 {dip_ma60:,.0f}) / 새 생명선 {life:,.0f}'))
|
| 711 |
-
phase='PEAK'; peak_gap=gap; peak_m60=m60
|
| 712 |
endlow_gap=0.0; endlow_ma60=HI; endlow_px=HI
|
| 713 |
hold=False; wave=0; armed=False; b240={}; flag240up=False
|
| 714 |
daily_open=False; pend=[]; up_peak=0.0; up_days=0
|
|
@@ -765,7 +767,7 @@ def run(df, tf='5min', sf=None, sell_dates=None, vcp_wins=None, block_ranges=Non
|
|
| 765 |
# ★ 마지막 봉 기준 '지금 상태' 한 줄 요약 (full_debug/app이 be.LAST_STATUS로 읽음). 반환값은 안 바꿈.
|
| 766 |
# LAST_STATUS_KIND: 색칠용 종류 — 'buy'(매수국면,빨강) / 'danger'(무너지는중,주황) / 'dip'(눌림판정)
|
| 767 |
# / 'done'(매수끝) / 'wait'(관망)
|
| 768 |
-
global LAST_STATUS, LAST_STATUS_KIND, LAST_STATUS_SHORT
|
| 769 |
try:
|
| 770 |
_g = f"{gap*100:+.1f}%" if 'gap' in dir() else ''
|
| 771 |
_gap_txt = f"60선이 240선보다 {_g}" if _g else ''
|
|
@@ -773,62 +775,56 @@ def run(df, tf='5min', sf=None, sell_dates=None, vcp_wins=None, block_ranges=Non
|
|
| 773 |
_mtn_nm = {1:'첫 산', 2:'더블산(2번째)', 3:'트리플산(3번째)'}.get(mtn_count, f'{mtn_count}번째 산')
|
| 774 |
if phase=='WAIT':
|
| 775 |
LAST_STATUS_SHORT = '관망'
|
| 776 |
-
|
| 777 |
LAST_STATUS_KIND = 'wait'
|
| 778 |
elif phase=='PEAK':
|
|
|
|
| 779 |
if life_broken:
|
| 780 |
LAST_STATUS_SHORT = '무너지는 중'
|
| 781 |
-
|
| 782 |
-
f"산 실패로 보고 있고, 60선이 시작보다 높게 끝나면 그때 다시 성공 인정")
|
| 783 |
LAST_STATUS_KIND = 'danger'
|
| 784 |
elif above:
|
| 785 |
-
# 60선이 240선 위 = 산봉우리 올라가는 중
|
| 786 |
LAST_STATUS_SHORT = f'{str(mtn_sdt)[:10]} 시작하는 동산 그리는 중'
|
| 787 |
-
|
| 788 |
-
f"시작 바닥 {str(mtn_sdt)[:10]}(60선 {mtn_s60:,.0f}), 봉우리 최고 +{peak_gap*100:.1f}% / 생명선 {life:,.0f}")
|
| 789 |
LAST_STATUS_KIND = 'wait'
|
| 790 |
else:
|
| 791 |
-
# 60선이 240선 아래로 내려옴 = 끝지점 가는 중
|
| 792 |
LAST_STATUS_SHORT = f'{str(mtn_sdt)[:10]} 시작하는 동산 후 끝지점 가는 중'
|
| 793 |
-
|
| 794 |
-
f"시작 바닥 {str(mtn_sdt)[:10]}(60선 {mtn_s60:,.0f}), 봉우리 최고 +{peak_gap*100:.1f}% / 생명선 {life:,.0f}")
|
| 795 |
LAST_STATUS_KIND = 'wait'
|
| 796 |
elif phase=='DIP':
|
| 797 |
_durd = (idx[-1]-dip_start_dt).days if dip_start_dt is not None else 0
|
| 798 |
LAST_STATUS_SHORT = '눌림 판정(매수멈춤)'
|
| 799 |
-
|
| 800 |
-
|
| 801 |
LAST_STATUS_KIND = 'dip'
|
| 802 |
elif phase=='WAVE':
|
| 803 |
if flag240up:
|
| 804 |
LAST_STATUS_SHORT = '매수 끝(쉬는 중)'
|
| 805 |
-
|
| 806 |
LAST_STATUS_KIND = 'done'
|
| 807 |
elif daily_open:
|
| 808 |
-
if up_days
|
| 809 |
-
_ud = f"지금은 60선 위로 튐({up_days}봉째) — 잠깐 매수 쉬는 중"
|
| 810 |
-
else:
|
| 811 |
-
_ud = "지금 60선 밑 — 매수 중"
|
| 812 |
LAST_STATUS_SHORT = '매수 국면'
|
| 813 |
-
|
| 814 |
LAST_STATUS_KIND = 'buy'
|
| 815 |
elif wave==0:
|
| 816 |
if wave_confirmed:
|
| 817 |
LAST_STATUS_SHORT = '매수 국면(대기)'
|
| 818 |
-
|
| 819 |
LAST_STATUS_KIND = 'buy'
|
| 820 |
else:
|
| 821 |
LAST_STATUS_SHORT = '복귀 확인 대기'
|
| 822 |
-
|
| 823 |
LAST_STATUS_KIND = 'wait'
|
| 824 |
else:
|
| 825 |
LAST_STATUS_SHORT = '위 구간 대기'
|
| 826 |
-
|
| 827 |
LAST_STATUS_KIND = 'wait'
|
| 828 |
else:
|
| 829 |
-
LAST_STATUS_SHORT = phase;
|
|
|
|
| 830 |
except Exception as _e:
|
| 831 |
-
LAST_STATUS = f"(상태 요약 실패: {_e})"; LAST_STATUS_KIND = 'wait'
|
| 832 |
return ev,buys,mts
|
| 833 |
|
| 834 |
if __name__=='__main__':
|
|
|
|
| 198 |
LAST_STATUS = '' # be.run 후 '지금 상태' 한 줄 요약 (full_debug/app이 읽음)
|
| 199 |
LAST_STATUS_KIND = 'wait' # 상태 종류(색칠용): buy/danger/dip/done/wait
|
| 200 |
LAST_STATUS_SHORT = '' # 짧은 상태명(라벨용): '산봉우리 그리는 중' 등
|
| 201 |
+
LAST_STATUS_DETAIL = '' # 상태 상세(뒷부분): '시작 바닥 ... / 생명선 ...'
|
| 202 |
|
| 203 |
|
| 204 |
def run(df, tf='5min', sf=None, sell_dates=None, vcp_wins=None, block_ranges=None):
|
|
|
|
| 329 |
vlife=None; vseg_i=len(buys); vbreak_dt=None
|
| 330 |
mtn_s60 = m60; mtn_sdt = d
|
| 331 |
life = min(bl, life if life else bl)
|
| 332 |
+
phase='PEAK'; peak_gap=gap; peak_m60=m60; vlife=None; vbreak_dt=None; vseg_i=len(buys) # ★새 산 그리기 시작 → 옛 가상생명선 폐기
|
| 333 |
endlow_gap=0.0; endlow_ma60=HI; endlow_px=HI
|
| 334 |
hold=False; wave=0; armed=False; b240={}; flag240up=False
|
| 335 |
daily_open=False; pend=[]; up_peak=0.0; up_days=0
|
|
|
|
| 355 |
base_bbmin=HI # 새 동산 시작 → 베이스 추적 리셋
|
| 356 |
mtn_s60=start_ma60; mtn_sdt=start_dt # 이 동산의 시작점 고정
|
| 357 |
life_broken=False
|
| 358 |
+
phase='PEAK'; peak_gap=gap; peak_m60=m60; vlife=None; vbreak_dt=None; vseg_i=len(buys) # ★새 산 그리기 시작 → 옛 가상생명선 폐기
|
| 359 |
endlow_gap=0.0; endlow_ma60=HI; endlow_px=HI
|
| 360 |
ev.append((d,'산봉우리시작',f'동산 시작점 {str(mtn_sdt)[:10]} (60선 {mtn_s60:,.0f}) / 생명선 {life:,.0f}'))
|
| 361 |
|
|
|
|
| 394 |
life = min(endlow_bb60, endlow_bbpx)*(1-LIFELINE_MARGIN)
|
| 395 |
life_broken=False
|
| 396 |
mtn_count=1 # ★ 새 시퀀스의 첫 동산 → 위아래 매수 시작
|
| 397 |
+
vlife=None; vbreak_dt=None; vseg_i=len(buys) # ★새 동산성공 = 새 시퀀스 → 옛 가상생명선 폐기
|
| 398 |
wave_fresh=True # 동산 완성 직후 복귀 → 모자 체크 대상
|
| 399 |
one_wave=False # 새 동산 → 1·2번째 다 매수
|
| 400 |
wave_confirmed=False; conf_logged=False; touch_logged=False; cross_up_dt=None; wave_hat=0.0 # 복귀확인 리셋
|
|
|
|
| 626 |
f'깊이는 {dip_gap*100:.1f}%로 얕아도 이렇게 오래 끌면 눌림 아니라 무너짐')
|
| 627 |
ev.append((d,_tag0,
|
| 628 |
f'속았음 → 처음부터 다시 — {_rsn0} / 이번 봉우리는 직전 산보다 {(_pg0*100 if _pg0 is not None else 0):+.1f}%({_why0}) / 240선 복귀 안 기다리고 위아래 접음 / 새 시작점 {str(dip_dt)[:10]}(60선 {dip_ma60:,.0f}) / 새 생명선 {life:,.0f}'))
|
| 629 |
+
phase='PEAK'; peak_gap=gap; peak_m60=m60; vlife=None; vbreak_dt=None; vseg_i=len(buys) # ★새 산 그리기 시작 → 옛 가상생명선 폐기
|
| 630 |
endlow_gap=0.0; endlow_ma60=HI; endlow_px=HI
|
| 631 |
hold=False; wave=0; armed=False; b240={}; flag240up=False
|
| 632 |
daily_open=False; pend=[]; up_peak=0.0; up_days=0
|
|
|
|
| 692 |
life = min(dip_bb60, dip_bbpx)*(1-LIFELINE_MARGIN)
|
| 693 |
ev.append((d,'깊은눌림→새동산(재베이스)',
|
| 694 |
f'한 바퀴 다 돌고 무너짐 → 처음부터 다시 — 봉우리가 직전 산보다 +{_pg*100:.1f}% 크게 올랐다가(기준 +{DOUBLE_MTN_GAP*100:.0f}% 넘음) 60선이 240선 밑으로 {dip_gap*100:.1f}% 깊이 빠짐(기준 -{emin*100:.0f}% 이하) / 새 시작점 {str(dip_dt)[:10]}(60선 {dip_ma60:,.0f}) / 새 생명선 {life:,.0f}'))
|
| 695 |
+
phase='PEAK'; peak_gap=gap; peak_m60=m60; vlife=None; vbreak_dt=None; vseg_i=len(buys) # ★새 산 그리기 시작 → 옛 가상생명선 폐기
|
| 696 |
endlow_gap=0.0; endlow_ma60=HI; endlow_px=HI
|
| 697 |
hold=False; wave=0; armed=False; b240={}; flag240up=False
|
| 698 |
daily_open=False; pend=[]; up_peak=0.0; up_days=0
|
|
|
|
| 710 |
else ('끝지점 낮아짐' if not _end_ok else '피크데이터 없음'))
|
| 711 |
ev.append((d,'속음→재베이스(깊은붕괴)',
|
| 712 |
f'속았음 → 처음부터 다시 — 60선이 240선 밑으로 {dip_gap*100:.1f}% 깊이 빠짐(기준 -{REBASE_DEEP_PCT*100:.0f}% 이하) + 봉우리가 직전 산보다 {(_pg*100 if _pg is not None else 0):+.1f}%({_whyR}). 위아래 아님 / 새 시작점 {str(dip_dt)[:10]}(60선 {dip_ma60:,.0f}) / 새 생명선 {life:,.0f}'))
|
| 713 |
+
phase='PEAK'; peak_gap=gap; peak_m60=m60; vlife=None; vbreak_dt=None; vseg_i=len(buys) # ★새 산 그리기 시작 → 옛 가상생명선 폐기
|
| 714 |
endlow_gap=0.0; endlow_ma60=HI; endlow_px=HI
|
| 715 |
hold=False; wave=0; armed=False; b240={}; flag240up=False
|
| 716 |
daily_open=False; pend=[]; up_peak=0.0; up_days=0
|
|
|
|
| 767 |
# ★ 마지막 봉 기준 '지금 상태' 한 줄 요약 (full_debug/app이 be.LAST_STATUS로 읽음). 반환값은 안 바꿈.
|
| 768 |
# LAST_STATUS_KIND: 색칠용 종류 — 'buy'(매수국면,빨강) / 'danger'(무너지는중,주황) / 'dip'(눌림판정)
|
| 769 |
# / 'done'(매수끝) / 'wait'(관망)
|
| 770 |
+
global LAST_STATUS, LAST_STATUS_KIND, LAST_STATUS_SHORT, LAST_STATUS_DETAIL
|
| 771 |
try:
|
| 772 |
_g = f"{gap*100:+.1f}%" if 'gap' in dir() else ''
|
| 773 |
_gap_txt = f"60선이 240선보다 {_g}" if _g else ''
|
|
|
|
| 775 |
_mtn_nm = {1:'첫 산', 2:'더블산(2번째)', 3:'트리플산(3번째)'}.get(mtn_count, f'{mtn_count}번째 산')
|
| 776 |
if phase=='WAIT':
|
| 777 |
LAST_STATUS_SHORT = '관망'
|
| 778 |
+
LAST_STATUS_DETAIL = '아직 산 시작 안 함 (60선이 240선 아래에서 바닥 다지는 중)'
|
| 779 |
LAST_STATUS_KIND = 'wait'
|
| 780 |
elif phase=='PEAK':
|
| 781 |
+
_pk_detail = f"시작 바닥 {str(mtn_sdt)[:10]}(60선 {mtn_s60:,.0f}), 봉우리 최고 +{peak_gap*100:.1f}% / 생명선 {life:,.0f}"
|
| 782 |
if life_broken:
|
| 783 |
LAST_STATUS_SHORT = '무너지는 중'
|
| 784 |
+
LAST_STATUS_DETAIL = f"생명선 {life:,.0f} 아래로 내려감(손절됨). 60선이 시작보다 높게 끝나면 그때 다시 성공 인정"
|
|
|
|
| 785 |
LAST_STATUS_KIND = 'danger'
|
| 786 |
elif above:
|
|
|
|
| 787 |
LAST_STATUS_SHORT = f'{str(mtn_sdt)[:10]} 시작하는 동산 그리는 중'
|
| 788 |
+
LAST_STATUS_DETAIL = _pk_detail
|
|
|
|
| 789 |
LAST_STATUS_KIND = 'wait'
|
| 790 |
else:
|
|
|
|
| 791 |
LAST_STATUS_SHORT = f'{str(mtn_sdt)[:10]} 시작하는 동산 후 끝지점 가는 중'
|
| 792 |
+
LAST_STATUS_DETAIL = _pk_detail
|
|
|
|
| 793 |
LAST_STATUS_KIND = 'wait'
|
| 794 |
elif phase=='DIP':
|
| 795 |
_durd = (idx[-1]-dip_start_dt).days if dip_start_dt is not None else 0
|
| 796 |
LAST_STATUS_SHORT = '눌림 판정(매수멈춤)'
|
| 797 |
+
LAST_STATUS_DETAIL = (f"{str(dip_start_dt)[:10]}부터 {_durd}일째, 지금 60선이 240선보다 {dip_gap*100:.1f}% "
|
| 798 |
+
f"(더블동산인지 무너진 건지 지켜보는 중)")
|
| 799 |
LAST_STATUS_KIND = 'dip'
|
| 800 |
elif phase=='WAVE':
|
| 801 |
if flag240up:
|
| 802 |
LAST_STATUS_SHORT = '매수 끝(쉬는 중)'
|
| 803 |
+
LAST_STATUS_DETAIL = f"2번째까지 다 삼 — 다시 240선 아래로 꺾일 때까지 쉬는 중 ({_gap_txt})"
|
| 804 |
LAST_STATUS_KIND = 'done'
|
| 805 |
elif daily_open:
|
| 806 |
+
_ud = f"지금은 60선 위로 튐({up_days}봉째) — 잠깐 매수 쉬는 중" if up_days else "지금 60선 밑 — 매수 중"
|
|
|
|
|
|
|
|
|
|
| 807 |
LAST_STATUS_SHORT = '매수 국면'
|
| 808 |
+
LAST_STATUS_DETAIL = f"{_mtn_nm}에서 {wave}번째 눌림 매수 중. {_ud} ({_gap_txt})"
|
| 809 |
LAST_STATUS_KIND = 'buy'
|
| 810 |
elif wave==0:
|
| 811 |
if wave_confirmed:
|
| 812 |
LAST_STATUS_SHORT = '매수 국면(대기)'
|
| 813 |
+
LAST_STATUS_DETAIL = f"{_mtn_nm} 위아래 열림, 1번째 눌림 대기(복귀 확인됨, 60선 밑으로 오면 매수) ({_gap_txt})"
|
| 814 |
LAST_STATUS_KIND = 'buy'
|
| 815 |
else:
|
| 816 |
LAST_STATUS_SHORT = '복귀 확인 대기'
|
| 817 |
+
LAST_STATUS_DETAIL = f"{_mtn_nm} 위아래 열렸지만 가짜(모자)일 수 있어 아직 매수 전 ({_gap_txt})"
|
| 818 |
LAST_STATUS_KIND = 'wait'
|
| 819 |
else:
|
| 820 |
LAST_STATUS_SHORT = '위 구간 대기'
|
| 821 |
+
LAST_STATUS_DETAIL = f"{_mtn_nm} · {wave}번째 눌림 후 위 구간 대기 중 ({_gap_txt})"
|
| 822 |
LAST_STATUS_KIND = 'wait'
|
| 823 |
else:
|
| 824 |
+
LAST_STATUS_SHORT = phase; LAST_STATUS_DETAIL = ''; LAST_STATUS_KIND = 'wait'
|
| 825 |
+
LAST_STATUS = f"{LAST_STATUS_SHORT} — {LAST_STATUS_DETAIL}" if LAST_STATUS_DETAIL else LAST_STATUS_SHORT
|
| 826 |
except Exception as _e:
|
| 827 |
+
LAST_STATUS = f"(상태 요약 실패: {_e})"; LAST_STATUS_KIND = 'wait'; LAST_STATUS_SHORT=''; LAST_STATUS_DETAIL=''
|
| 828 |
return ev,buys,mts
|
| 829 |
|
| 830 |
if __name__=='__main__':
|