Skip to content

tomchaccom/Fin_AI_Agent

Repository files navigation

미래에셋 TECH 부문 공모전

  • 사용자의 질문에 신뢰성있게 답변하는 금융 AI Agent 개발

시스템 아키텍쳐

image

기술 스택

기술 스택 설명
Python 프로젝트의 메인 로직 및 데이터 처리를 담당하는 프로그래밍 언어
LangGraph 복잡한 상태 관리와 순환 흐름을 가진 멀티 에이전트 워크플로우 구축
LangChain LLM(대규모 언어 모델)과의 상호작용 및 체인 구성을 위한 프레임워크
FastAPI 비동기 처리를 지원하는 고성능 API 서버 엔진
Naver Cloud Platform 서비스 배포 및 클라우드 인프라 자원 관리

API 콜 양식

http://175.45.200.187:8000/agent?question=삼성전자 종가를 알려줘 의 형식으로 작성해주세요

GET /agent?question=거래량이 전날 대비 15% 이상 오른 종목을 모두 보여줘 HTTP/1.1
Host: your.server.ip:8000
Authorization: Bearer nv-xxxxxxxxxxxxxxxxxxxxxxxx
X-NCP-CLOVASTUDIO-REQUEST-ID: test-local-123

코드 설명

rag_stock_pipeline.py

  • 역할: 종목명 및 주식 관련 용어의 전처리 파이프라인을 담당합니다.
  • 주요 기능: 종목 약어 및 주식 은어(슬랭)를 표준화된 형태로 정제합니다.

SparseRetriever 와 DenseRetriever의 앙상블 기법을 활용하여 변환할 종목 은어 리스트 추출 후 리랭커를 통해서 제일 적합한 단어를 선택

noTask.py

  • 역할: 분류되지 않은 사용자 질문(미분류 테스크)을 처리하고, 재작성하여 의미를 명확히 합니다.
  • 주요 기능: 시스템이 정의한 주요 테스크(단순 조회, 조건 검색, 시그널 감지)에 해당하지 않는 질문을 '테스크화'하는 로직을 수행합니다.

주가 상승/하락과 관련된 질문을 RSI, 골든/데드크로스 등의 구체적인 시그널 형태로 변환하는 기능을 포함합니다.

task_classification.py

  • 역할: 사용자 질문의 의도를 분석하여 사전에 정의된 테스크 중 하나로 분류합니다.

  • 주요 기능: 사용자 질문을 다음 세 가지 테스크 유형 중 하나로 분류합니다:

    • 단순 조회: 특정 정보에 대한 직접적인 질문 (예: "삼성전자 주가 얼마야?")

    • 조건 검색: 특정 조건에 맞는 종목을 찾는 질문 (예: "어제 거래량 10% 이상 증가한 종목 찾아줘")

    • 시그널 감지: 기술적 지표나 시장 시그널을 감지하는 질문 (예: "골든크로스 발생한 종목 알려줘")

stock_db.py, scheduler.py###

  • 역할: 주가 데이터를 관리하고 업데이트를 자동화
  • 주요 기능: stock_db.py: 주가 데이터를 데이터베이스에 저장하고 관리하는 로직을 포함
  • scheduler.py: 매일 장 마감 시점인 17:30에 자동으로 실행되도록 설정되어 하루치 주가 데이터를 데이터베이스에 저장하는 역할

graph.py

역할: 전체 질의응답 처리 흐름을 연결하는 메인 워크플로우를 정의하며, LangGraph 기반으로 구축

 → 단어 전처리 (종목 약어, 주식 은어 정제)
 → 테스크 분류기 
 → 에이전트 호출
 → 결과 생성

   └─ 미분류된 테스크인 경우:
       → 미분류 처리기 (`noTask.py`)
       → 에이전트로 연결

agent.py 워크플로우

image

AI 에이전트 주식 도구 사용 가이드

주식 분석을 위한 8개의 주요 함수(tool)

  1. 주식_데이터_조회_종목명 - 특정 종목의 주가 데이터 조회
  2. 주식_데이터_조회_모든_종목 - 특정 날짜의 모든 종목 데이터 조회
  3. 종목_필터_단일 - 단일 조건으로 종목 필터링
  4. 종목_필터_비교 - 두 시점 데이터 비교하여 필터링
  5. 종목_합집합 - 두 종목 리스트의 합집합
  6. 종목_교집합 - 두 종목 리스트의 교집합
  7. 종목_차집합 - 두 종목 리스트의 차집합
  8. 종목_XOR집합 - 두 종목 리스트의 XOR집합

함수 사용법

1. 주식_데이터_조회_종목명

특정 종목의 주가 데이터를 조회합니다.

# 사용 예시
result = 주식_데이터_조회_종목명("삼성전자", "2024-01-02", "2024-01-05")

반환 데이터 구조:

[
  {
    "날짜시간": "2024-01-02T00:00:00",
    "시가": 75000,
    "고가": 76000,
    "저가": 74500,
    "종가": 75500,
    "판매량": 15000000
  }
]

2. 주식_데이터_조회_모든_종목

특정 날짜의 모든 종목 데이터를 조회합니다.

# 사용 예시
kospi_stocks = 주식_데이터_조회_모든_종목("KOSPI", "2024-01-02")
kosdaq_stocks = 주식_데이터_조회_모든_종목("KOSDAQ", "2024-01-02")
all_stocks = 주식_데이터_조회_모든_종목("ALL", "2024-01-02")

반환 데이터 구조:

[
  {
    "종목명": "삼성전자",
    "종목코드": "005930",
    "거래이력": [
      {
        "날짜시간": "2024-01-02T00:00:00",
        "시가": 75000,
        "고가": 76000,
        "저가": 74500,
        "종가": 75500,
        "판매량": 15000000
      }
    ]
  }
]

3. 종목_필터_단일

단일 조건으로 종목을 필터링합니다.

# 종가가 50000원 이상인 종목 찾기
high_price_stocks = 종목_필터_단일(
    stock_data,  # 종목 데이터 리스트
    "종가",      # 수식
    ">=",        # 조건
    50000        # 임계값
)

# 거래량이 1000만주 이상인 종목 찾기
high_volume_stocks = 종목_필터_단일(
    stock_data,
    "판매량",
    ">=",
    10000000
)

# 복합 수식 사용 예시 (시가대비 종가 상승률)
rising_stocks = 종목_필터_단일(
    stock_data,
    "(종가-시가)/시가*100",  # 수익률 계산
    ">",
    5.0  # 5% 이상 상승
)

사용 가능한 변수:

  • 시가, 고가, 저가, 종가, 판매량

사용 가능한 조건:

  • >, <, >=, <=, =, !=

4. 종목_필터_비교

두 시점의 데이터를 비교하여 필터링합니다.

# 전날보다 거래량이 3배 이상 증가한 종목 찾기
volume_surge_stocks = 종목_필터_비교(
    today_stocks,      # 비교대상 (오늘)
    yesterday_stocks,  # 비교군 (어제)
    "비교대상_판매량/비교군_판매량",  # 거래량 비율
    ">=",
    3.0  # 3배 이상
)

# 전날보다 주가가 10% 이상 상승한 종목 찾기
price_surge_stocks = 종목_필터_비교(
    today_stocks,
    yesterday_stocks,
    "(비교대상_종가-비교군_종가)/비교군_종가*100",  # 수익률
    ">=",
    10.0  # 10% 이상
)

사용 가능한 변수:

  • 비교대상: 비교대상_시가, 비교대상_고가, 비교대상_저가, 비교대상_종가, 비교대상_판매량
  • 비교군: 비교군_시가, 비교군_고가, 비교군_저가, 비교군_종가, 비교군_판매량

5-8. 집합 연산

# 합집합: 두 조건 중 하나라도 만족하는 종목
union_stocks = 종목_합집합(high_price_stocks, high_volume_stocks)

# 교집합: 두 조건을 모두 만족하는 종목
intersection_stocks = 종목_교집합(high_price_stocks, high_volume_stocks)

# 차집합: 첫 번째 조건만 만족하는 종목
difference_stocks = 종목_차집합(high_price_stocks, high_volume_stocks)

# XOR집합: 한 조건만 만족하는 종목 (둘 다 만족하거나 둘 다 불만족하는 것 제외)
xor_stocks = 종목_XOR집합(high_price_stocks, high_volume_stocks)

실전 사용 시나리오

시나리오 1: 급등주 찾기

# 1단계: 오늘과 어제 데이터 조회
today_data = 주식_데이터_조회_모든_종목("KOSPI", "2024-01-03")
yesterday_data = 주식_데이터_조회_모든_종목("KOSPI", "2024-01-02")

# 2단계: 거래량 급증 종목 찾기 (전날 대비 2배 이상)
volume_surge = 종목_필터_비교(
    today_data,
    yesterday_data,
    "비교대상_판매량/비교군_판매량",
    ">=",
    2.0
)

# 3단계: 주가 상승 종목 찾기 (5% 이상)
price_rise = 종목_필터_비교(
    today_data,
    yesterday_data,
    "(비교대상_종가-비교군_종가)/비교군_종가*100",
    ">=",
    5.0
)

# 4단계: 두 조건을 모두 만족하는 급등주 찾기
hot_stocks = 종목_교집합(volume_surge, price_rise)

시나리오 2: 대형주 중 저평가 종목 찾기

# 1단계: 전체 데이터 조회
all_stocks = 주식_데이터_조회_모든_종목("KOSPI", "2024-01-02")

# 2단계: 대형주 필터링 (시가총액 대신 거래량으로 대체)
large_cap = 종목_필터_단일(
    all_stocks,
    "판매량",
    ">=",
    5000000  # 500만주 이상
)

# 3단계: 저가주 필터링
low_price = 종목_필터_단일(
    all_stocks,
    "종가",
    "<=",
    100000  # 10만원 이하
)

# 4단계: 대형주이면서 저가인 종목
value_stocks = 종목_교집합(large_cap, low_price)

시나리오 3: 섹터 로테이션 분석

# 1단계: 두 섹터 대표 종목들 데이터 조회
tech_stocks = 주식_데이터_조회_모든_종목("KOSDAQ", "2024-01-02")  # 기술주
traditional_stocks = 주식_데이터_조회_모든_종목("KOSPI", "2024-01-02")  # 전통주

# 2단계: 각 섹터에서 상승 종목 찾기
tech_rising = 종목_필터_단일(
    tech_stocks,
    "(종가-시가)/시가*100",
    ">",
    3.0
)

traditional_rising = 종목_필터_단일(
    traditional_stocks,
    "(종가-시가)/시가*100",
    ">",
    3.0
)

# 3단계: 섹터별 강세 비교
tech_strength = len(tech_rising)
traditional_strength = len(traditional_rising)

팁과 주의사항

1. 데이터 조회 순서

  • 항상 주식_데이터_조회_모든_종목 또는 주식_데이터_조회_종목명으로 시작
  • 필터링은 조회된 데이터에 순차적으로 적용

2. 수식 작성 팁

  • 괄호를 적절히 사용하여 연산 순서 명확화
  • 나눗셈 시 0으로 나누는 경우 자동으로 필터링됨
  • 퍼센트 계산 시 100을 곱해야 함: (종가-시가)/시가*100

3. 성능 최적화

  • 큰 데이터셋은 여러 단계로 나누어 필터링
  • 불필요한 데이터 조회 피하기
  • 집합 연산 전에 개별 필터링 먼저 수행

4. 오류 처리

  • 데이터가 없는 날짜 조회 시 빈 리스트 반환
  • 잘못된 종목명 입력 시 빈 리스트 반환
  • 수식 오류 시 해당 종목은 자동으로 제외

데이터 형식 참고

모든 함수의 입력과 출력은 일관된 딕셔너리 형식을 사용합니다:

{
  "종목명": "string",
  "종목코드": "string", 
  "거래이력": [
    {
      "날짜시간": "ISO 형식 날짜시간",
      "시가": "number",
      "고가": "number", 
      "저가": "number",
      "종가": "number",
      "판매량": "integer"
    }
  ]
}

이 형식을 유지하면서 함수들을 연결하여 복잡한 주식 분석 파이프라인을 구성할 수 있습니다.

느낀점

명성: 저는 데이터 변환 및 전처리 agent가 사용할 도구 함수를 만드는 역할을 맡았습니다. 가장 어려웠던 부분은 신뢰성 있는 답변을 내기 위해 사용자의 질문에 포함된 주식 약어, 슬랭을 적절한 의미로 변경하는 것이었습니다. 단일 LLM을 이용하거나 은어-> 변환될 단어 의 매핑테이블로만은 적절한 변환이 어려웠는데 이 kospi, kosdaq의 모든 종목명을 RAG해둔 데이터를 이용해서, 의미 기반(sparse), 유사도 기반(Dense) retriever를 앙상블 하고, 의미에 좀더 가중치를 둔 뒤 실제 변환될 단어의 목록들과 사용자의 질문을 보고 Reranker를 통해서 현재 문맥에 가장 적합한 단어를 선택하는 변환 과정을 설계하는 것이었습니다. 이렇게 처리하니 신뢰성 있는 질문으로 재생성이 가능했고 도구 같은 경우는 RSI, 골든,데드 크로스와 같은 경우는 정량적인 수치값을 이용해서 발생하는 현상을 체크하는 것이기 때문에 어렵지 않게 만들 수 있었습니다.

👨‍💻 Developers

김명성 김태민
Data preprocessing
deployment / Agent tool
Agent CoT / DB Schema
GitHub GitHub

About

미래에셋 AI 공모전 AI agent

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages