매수가능조회_설정값_역할및_코드영향_분석

종목선정 탭 · 매수가능조회 영역 설정값 역할 및 코드 영향 분석

작성 목적: 종목선정 탭의 매수가능조회 영역에 노출된 설정값(탈출가비율, 타임컷, 컷수익, 손절, 갭Low/Mid/High, 본전기준)의 역할·영향을 정리하고, 코드베이스 반영 여부 및 매수·매도 방향 가이드를 제공한다.

대상 UI:

  • PC: irm/frontend/src/App.tsx — 종목선정 탭 내 “매수가능조회” 블록 + 설정 1·2행
  • 모바일: irm/frontend_mobile/src/App.tsx — 동일 설정 항목

1. 설정값 요약 및 DB/API 매핑

UI 라벨 DB/API 필드 기본값 단위 비고
탈출가비율 exit_percentage 5.0 % 하향 탈출가 = 매수가 × (1 - 값/100)
타임컷(분) time_cut_minutes 20 타임컷 적용 경과 시간
컷수익 time_cut_profit_min 1.0 % 타임컷 시 “수익 부진” 기준 최소 수익률
손절 hard_stop_rate -3.0 % 하한 수익률 이탈 시 즉시 매도
갭Low gap_low 3.0 % 동적 갭: 최고 수익률 0~3% 미만 구간
갭Mid gap_mid 1.5 % 동적 갭: 3%~7% 미만 구간
갭High gap_high 1.0 % 동적 갭: 7% 이상 구간
본전기준 break_even_threshold 2.0 % 본전 보장 적용 최소 수익률
  • 저장 위치: 사용자·환경별 user_environment_settings (실전/모의 분리), 없으면 users 테이블 폴백.
  • API: GET/PUT /api/v1/user/settings 에서 위 필드 조회·저장.

2. 각 설정값의 역할과 영향

2.1 탈출가비율 (exit_percentage)

  • 역할: 매수 직후 하향 탈출가를 정하는 비율.
    하향 탈출가 = 매수가 × (1 - 탈출가비율/100)
    현재가가 이 가격 이하로 내려가면 “하향 탈출”로 매도 대상이 됨.
  • 추가 동작:
    • 가격이 올라가면 “최고가”가 갱신되고, 그 최고가 기준으로 동일 비율로 하향 탈출가가 다시 계산됨(트레일링 형태).
    • 상향 탈출가는 별도 설정(목표가)이며, 이 비율과는 무관.
  • 매수와의 관계:
    매수 시점에 “얼마만큼 떨어지면 손절할지” 리스크 범위를 정하는 값.
    비율을 크게 하면 하락 허용 폭이 커지고, 작게 하면 조기 하향 매도에 가깝게 동작.

코드 위치

  • irm/backend/services/exit_point_manager.py: _get_user_exit_percentage, set_exit_point, update_exit_point
  • irm/backend/services/exit_point_store.py: 탈출가 계산
  • irm/backend/api/restful/routes.py: 매수 시 exit_percentage 전달 시 해당 값으로 탈출지점 설정

2.2 타임컷(분) (time_cut_minutes) · 컷수익 (time_cut_profit_min)

  • 역할:

    • 타임컷(분): 매수 후 경과 시간(분).
    • 컷수익: “이 수익률 미만이면 수익 부진”으로 보는 기준(%).

    조건: 경과분 >= 타임컷(분) 이고 현재 수익률 < 컷수익 이면 타임컷 매도 발생.
    → “일정 시간 지났는데 수익이 너무 적으면 매도하고 다른 종목으로 교체”하는 로직.

  • 매수와의 관계:
    직접적으로 “무엇을 매수할지”를 정하지는 않음.
    매수 후 보유 시간과 최소 수익 기대를 정해서, 지루한 종목을 정리하고 재진입/교체 매수로 이어지게 하는 매도·재진입 방향을 잡는 설정.

코드 위치

  • irm/backend/services/trader.py: check_sell_signal 내 Step 1 — elapsed_minutes >= tc_min and current_profit_rate < tc_profit 일 때 타임컷 매도 반환.

2.3 손절 (hard_stop_rate)

  • 역할: 하한 수익률(%) 이탈 시 즉시 매도.
    현재 수익률 <= 손절 이면 “손절” 사유로 매도 신호.
  • 매수와의 관계:
    매수 종목 선정에는 관여하지 않음.
    다만 재진입 필터에서 “당일 손절/본전(수익률 ≤ 0) 매도한 종목”은 60분 쿨타임 후에만 재진입 가능하므로, 손절로 매도된 종목은 일정 시간 동안 재매수에서 제외되는 간접적 매수(재진입) 영향이 있음.

코드 위치

  • irm/backend/services/trader.py: check_sell_signal Step 2 — current_profit_rate <= hard_stop
  • irm/backend/services/stock_selection_runner.py: 재진입 필터에서 profit_rate_pct <= 0 인 경우 60분 쿨타임(손절/본전 동일 취급)

2.4 갭Low · 갭Mid · 갭High (gap_low, gap_mid, gap_high)

  • 역할: 동적 트레일링 스탑용 갭(%).
    매수 후 최고 수익률 구간에 따라 허용 하락 폭이 달라짐.

    최고 수익률 구간 사용 갭
    0% ~ 3% 미만 갭Low
    3% ~ 7% 미만 갭Mid
    7% 이상 갭High

    계산: 트레일링 스탑가 = 최고가 × (1 - 갭/100).
    현재가가 이 가격 아래로 내려가면 트레일링 스탑 매도.

  • 매수와의 관계:
    어떤 종목을 매수할지에는 미사용.
    “얼마 올랐을 때 얼마만큼만 되돌리면 매도할지”를 정하는 매도 방향 설정.
    갭을 크게 하면 되돌림을 더 허용(보유 유지), 작게 하면 조기 익절에 가깝게 동작.

코드 위치

  • irm/backend/services/trader.py: _get_gap_for_max_profit, check_sell_signal Step 3

2.5 본전기준 (break_even_threshold)

  • 역할: 본전 보장 적용 조건.
    한 번이라도 최고 수익률이 본전기준 이상이 되었으면, 트레일링 스탑가가 매수가(본전) 아래로 내려가지 않도록 올려서, 본전 이하에서는 매도하지 않음.
  • 매수와의 관계:
    매수 종목 선정에는 미사용.
    “일정 수익까지 갔다가 되돌아와도 최소한 본전에서는 팔리게” 하는 매도 방어 설정.
    값이 크면 “본전 보장이 걸리기까지 필요한 수익”이 커짐.

코드 위치

  • irm/backend/services/trader.py: check_sell_signal Step 3 — max_profit_rate >= break_even and calculated_stop_price < buy_price 일 때 calculated_stop_price = buy_price 로 상한

3. 코드베이스 영향 정리

3.1 실제로 설정값을 사용하는 모듈

모듈 사용 설정 용도
backend/services/exit_point_manager.py exit_percentage 하향 탈출가 계산(설정·갱신), 환경별 조회
backend/services/exit_point_store.py exit_percentage 탈출가 저장 시 계산
backend/services/trader.py time_cut_minutes, time_cut_profit_min, hard_stop_rate, gap_low/mid/high, break_even_threshold 4단계 매도 신호(타임컷, 손절, 트레일링, 목표가)
backend/api/restful/routes.py 전 항목 GET/PUT /api/v1/user/settings 조회·저장, 매수 시 exit_percentage 전달 반영
backend/model/database.py 전 항목 User, UserEnvironmentSettings 컬럼 정의
frontend/src/App.tsx, frontend_mobile/src/App.tsx 전 항목 매수가능조회 영역 설정 UI 및 저장 요청

3.2 모니터링·매도 흐름

  • monitor_loop: ExitPointManager.get_all_exit_points 로 탈출지점 조회 → 환경별 현재가 조회 → Trader.check_sell_signal(exit_point, current_price, user_id, user_settings=None) 호출.
  • user_settings=None 이면 Trader._load_user_settings(user_id)User 테이블만 조회하여 타임컷·컷수익·손절·갭·본전기준을 적용.

3.3 환경별 설정과의 불일치 가능성

  • API: GET/PUT /api/v1/user/settings 는 **현재 백엔드 환경(실전/모의)**에 따라 user_environment_settings 행이 있으면 해당 행을, 없으면 User 를 사용.
  • Trader: _load_user_settingsUser 테이블만 사용.
    → 실전/모의별로 다른 값을 두고 싶어도, 모니터링(매도 신호)에는 현재 User 테이블 값만 적용됨.
    → 실전/모의별로 탈출·타임컷·손절·갭·본전을 다르게 쓰려면, Trader에서도 환경별 UserEnvironmentSettings 를 참조하도록 수정이 필요함.

3.4 매수·재진입에만 쓰이는 개념

  • 탈출가비율: 매수 API 호출 시 탈출지점 설정에 사용되므로 매수 직후 리스크 범위에 직접 영향.
  • 손절/본전: 재진입 필터에서 “당일 손절/본전(수익률 ≤ 0) 매도” 이력이 있으면 60분 쿨타임.
    본전기준 수치 자체는 재진입 로직에서 사용하지 않고, “실제 매도 시 수익률이 0 이하인지”만 사용.

4. 매수 방향 가이드 (설정값이 매수·매도에 미치는 영향)

4.1 “매수”에 직접 영향을 주는 설정

  • 탈출가비율
    • 매수 시점에 “몇 % 떨어지면 하향 탈출할지”를 정함.
    • 높이면: 하락 허용 폭이 커져, 변동성 있는 종목을 조금 더 오래 붙들 수 있음.
    • 낮추면: 조금만 떨어져도 하향 탈출 → 보수적 매도.
    • 매수 “방향”이라기보다, 매수 후 리스크 한도를 정하는 값.

나머지(타임컷, 컷수익, 손절, 갭, 본전기준)는 매수 종목 선정 로직에는 사용되지 않음.
재진입만 “당일 손절/본전 여부 + 쿨타임”으로 제한되므로, 손절로 매도된 종목은 60분 동안 재매수 후보에서 제외된다는 점만 매수(재진입)에 영향을 줌.

4.2 “매도·재진입” 방향을 잡는 설정 (요약)

설정 값을 키우면 값을 줄이면
탈출가비율 하향 탈출이 더 넓은 하락에서 발생(보유 연장) 더 일찍 하향 탈출(보수적)
타임컷(분) 타임컷 매도가 더 늦게 발생 더 빨리 “수익 부진” 정리
컷수익 타임컷이 덜 걸림(낮은 수익도 허용) 타임컷이 더 잘 걸림(수익 부진 기준 강화)
손절 손절선이 더 아래(손실 더 허용) 손절선이 더 위(일찍 손절)
갭Low/Mid/High 트레일링 스탑이 느슨해짐(되돌림 더 허용) 트레일링 스탑이 타이트해짐(일찍 익절)
본전기준 본전 보장이 걸리려면 더 높은 수익 필요 더 낮은 수익에서도 본전 보장 적용

4.3 추천 조합 개념 (참고)

  • 공격적: 탈출가비율·갭을 크게, 타임컷(분) 길게, 컷수익 낮게, 손절선 여유 있게 → 보유 연장·재진입 기회 증가.
  • 보수적: 탈출가비율·갭 작게, 타임컷 짧게, 컷수익 높게, 손절선 타이트하게 → 일찍 정리·손실 제한.
  • 본전 우선: 본전기준을 2% 전후로 두고, 갭은 적당히 → 한 번 올랐다 내려와도 본전 이하 매도는 피함.

5. 설정 변경 시 모니터링 반영 여부 (코드베이스 조사)

질문: 종목 매수 후 모니터링 중에 사용자가 설정값(탈출가비율, 타임컷, 컷수익, 손절, 갭, 본전기준)을 변경하면, 모니터링이 변경된 값을 인지하여 반영하는가?

5.1 결론 요약

구분 반영 여부 조건·비고
타임컷, 컷수익, 손절, 갭Low/Mid/High, 본전기준 환경에 따라 다름 User 테이블에 저장된 경우에만 반영. UserEnvironmentSettings만 갱신된 경우에는 반영 안 됨.
탈출가비율 모니터링 루프에서는 미사용 현재 모니터링은 Trader.check_sell_signal만 사용하며, 하향 탈출가(exit_price)를 비교하지 않음. 변경해도 진행 중인 모니터링 판단에는 영향 없음.

5.2 동작 흐름 (코드 기준)

  1. 모니터링 루프 (irm/monitoring/monitor_loop.py)

    • 매 루프(약 1초 주기)마다 ExitPointManager.get_all_exit_points(uid, environment=None)로 탈출지점 목록 조회.
    • exit_point마다 Trader.check_sell_signal(exit_point, current_price, user_id, user_settings=None) 호출.
    • 항상 user_settings=None으로 호출 → 매번 Trader가 설정을 스스로 로드.
  2. Trader.check_sell_signal (irm/backend/services/trader.py)

    • if user_settings is None: 일 때 user_settings = Trader._load_user_settings(user_id) 실행.
    • 즉, 종목마다·루프마다 DB에서 설정을 다시 읽음 (캐시 없음).
  3. Trader._load_user_settings

    • User 테이블만 조회함. UserEnvironmentSettings는 조회하지 않음.
    • 반환 필드: time_cut_minutes, time_cut_profit_min, hard_stop_rate, gap_low, gap_mid, gap_high, break_even_threshold.
  4. PUT /api/v1/user/settings (irm/backend/api/restful/routes.py)

    • 현재 환경(실전/모의)에 해당하는 UserEnvironmentSettings 행이 있으면 해당 행만 갱신하고 User 테이블은 갱신하지 않음.
    • UserEnvironmentSettings 테이블이 없거나 오류 시에만 User 테이블을 갱신하는 폴백 경로 존재.

5.3 시나리오별 정리

  • UserEnvironmentSettings에만 저장되는 경우 (일반적인 경우)

    • UI에서 "설정 저장" 시 실전/모의별로 user_environment_settings 행만 갱신.
    • Trader는 User만 읽으므로 모니터링에는 변경값이 반영되지 않음.
    • 같은 프로세스가 계속 도는 한, 모니터링 재시작해도 Trader는 여전히 User만 보므로 반영 안 됨.
  • User 테이블에 저장되는 경우

    • user_environment_settings 미사용(테이블 없음 등)으로 API가 User만 갱신하는 경로로 저장한 경우.
    • 다음 루프에서 _load_user_settings가 새 값을 읽으므로 타임컷·컷수익·손절·갭·본전기준 변경이 곧바로 반영됨.
  • 탈출가비율

    • 매수 시점에 exit_price가 계산되어 exit_points 테이블에 저장됨.
    • 모니터링 루프에서는 Trader.check_sell_signal만 호출하며, 이 함수는 exit_point 내 exit_price를 사용하지 않음 (buy_price, highest_price, upper_exit_price만 사용).
    • 따라서 모니터링 중에 탈출가비율을 바꿔도, 이미 저장된 exit_price는 그대로이며, 현재 루프의 매도 여부 판단에는 반영 경로가 없음.
    • (최고가 갱신 시 탈출가를 다시 쓰는 ExitPointManager.update_exit_point는 모니터링 루프에서 호출되지 않음.)

5.4 개선 시 권장 사항

  • 타임컷·컷수익·손절·갭·본전기준이 실전/모의별로 곧바로 반영되려면:

    • Trader._load_user_settings(user_id)에서 **현재 모니터링 대상 환경(real/virtual)**을 인자로 받고,
    • 해당 환경에 대한 UserEnvironmentSettings 행을 우선 조회한 뒤, 없을 때만 User 테이블을 사용하도록 변경하는 것이 필요함.
    • 이때 모니터링 루프에서 check_sell_signal 호출 시 exit_point["environment"]를 전달할 수 있음.
  • 탈출가비율을 모니터링에 반영하려면:

    • 매 루프에서 최고가 갱신 시 ExitPointManager.update_exit_point를 호출해, 현재 사용자 설정 비율로 하향 탈출가를 재계산하거나,
    • 또는 Trader.check_sell_signal 내부에서 "현재가 ≤ (최고가 또는 매수가 기준 적용 비율)" 조건을 추가하는 방식이 필요함.
    • 현재는 Trader가 exit_point의 exit_price를 사용하지 않으므로, 설정 변경이 곧바로 반영되는 경로가 없음.

6. 참고 파일 목록

  • irm/backend/model/database.py — User, UserEnvironmentSettings 컬럼
  • irm/backend/services/trader.py — 4단계 매도 신호(타임컷, 손절, 동적 갭+본전, 목표가)
  • irm/backend/services/exit_point_manager.py — 탈출가 비율·설정·갱신
  • irm/backend/api/restful/routes.py — user settings API, 매수 시 exit_percentage
  • irm/monitoring/monitor_loop.py — 탈출지점 모니터링 및 Trader.check_sell_signal 호출
  • irm/backend/services/stock_selection_runner.py — 재진입 필터(손절/본전 60분 쿨)
  • irm/frontend/src/App.tsx, irm/frontend_mobile/src/App.tsx — 매수가능조회 영역 UI