미국 주식시장 뉴스API를 통한 Daily 증시 시황정리 프로그램

AI주식자동매매|2025. 6. 3. 18:20
반응형

make_summary.py 데이터 플로우 프로세스 메뉴얼

📋 프로그램 개요

목적: 미국 뉴스 API에서 분야별 Top-뉴스를 수집하고, OpenAI를 통해 섹션별 요약 및 추천 업종·종목을 생성하여 JSON 파일로 저장

주요 기능:

  • NewsAPI.org를 통한 미국 비즈니스 뉴스 수집
    Developer price 0$ 사용중: 100 requests over a 24 hour period (50 requests available every 12 hours)
  • OpenAI(o4-mini) 모델을 이용한 뉴스 요약 및 시장 분석
  • 섹션별 정리된 JSON 결과물 생성

🔄 전체 데이터 플로우

 
[시작] → [날짜 계산] → [뉴스 수집] → [데이터 통합] → [AI 분석] → [JSON 저장] → [종료]

📅 STEP 1: 날짜 계산 및 설정

🎯 목적

뉴욕 시간 기준으로 분석 대상 날짜 범위를 설정

📊 데이터 플로우

 
현재 시점(뉴욕 시간)
    ↓
target_date = 현재 - 5일 (분석 기준일)
    ↓
start_date = target_date - 5일 (검색 시작일)
    ↓
target_datetime = 타임스탬프 생성

🔧 함수: get_target_and_start_dates()

입력: 없음
출력:

  • target_date_str: "2025-05-29" (파일명용)
  • start_datetime_str: "2025-05-24 10:30:00" (정렬용)
  • start_date_str: "2025-05-24" (API 검색용)
  • now_ny: 뉴욕 현재 시간 객체

📝 실행 로그 예시

 
▶ Target date (NY 기준): 2025-05-29
▶ Target datetime (NY 기준): 2025-05-29 10:30:00
▶ Start date (5일 전): 2025-05-24

📰 STEP 2: 뉴스 데이터 수집

🎯 목적

NewsAPI를 통해 비즈니스 뉴스와 주요 키워드별 뉴스를 수집

📊 데이터 플로우

2-1. 비즈니스 헤드라인 수집

 
NewsAPI (top-headlines)
    ↓ category="business", country="us"
biz_raw (최대 20개 기사)
    ↓ publishedAt 기준 내림차순 정렬
biz_articles (상위 3개 선택)
    ↓
market_headlines 리스트 생성

2-2. 키워드별 뉴스 수집

 
6개 키워드 검색:
├── economics: "economic indicators"
├── ai_software: "AI software"  
├── ai_semiconductor: "AI semiconductor"
├── quantum: "quantum computing OR quantum networking"
├── ai_robotics: "AI robotics"
└── aerospace: "Aerospace & Defense"
    ↓
각 키워드별 NewsAPI (everything) 호출
    ↓ start_date ~ target_date 범위
raw_articles (최대 30개씩)
    ↓ publishedAt 기준 내림차순 정렬  
topics_articles[키워드] (상위 3개씩)

🔧 주요 함수들

fetch_headlines_with_image(category, country, page_size)

  • 입력: 카테고리, 국가, 페이지 크기
  • 출력: 정제된 기사 리스트
  • API: /v2/top-headlines

fetch_everything(query, from_date, to_date, page_size)

  • 입력: 검색어, 시작일, 종료일, 페이지 크기
  • 출력: 원본 기사 리스트
  • API: /v2/everything

📝 실행 로그 예시

 
▶ fetch_headlines_with_image 반환 기사 개수: 17
▶ biz_articles (상위 3개) 개수: 3
▶ economics 키워드, 상위 3개 뉴스 개수: 3
▶ ai_software 키워드, 상위 3개 뉴스 개수: 3

🔍 STEP 3: 콘텐츠 보강 (크롤링)

🎯 목적

NewsAPI에서 제공하는 짧은 스니펫을 실제 기사 본문으로 보강

📊 데이터 플로우

 
기사 스니펫 검사
    ↓ (길이 < 100자 OR 끝이 "…")
해당 기사 URL 크롤링
    ↓ BeautifulSoup으로 <p> 태그 추출
본문 텍스트 (최대 5,000자)
    ↓
기존 snippet 대체

🔧 함수: fetch_full_text(url, max_chars=5000)

  • 입력: 기사 URL, 최대 문자 수
  • 출력: 추출된 본문 텍스트
  • 오류 처리: 크롤링 실패 시 빈 문자열 반환

🗂️ STEP 4: 데이터 통합 및 구조화

🎯 목적

수집된 모든 기사를 섹션별로 분류하고 통합 데이터 구조 생성

📊 데이터 플로우

4-1. 전체 기사 리스트 생성

 
market_headlines (비즈니스 3개)
    ↓ category="미국 주식시장 동향" 추가
topics_articles (키워드별 3개씩)
    ↓ 한글 섹션명 매핑
        ├── economics → "주요 경제지표"
        ├── ai_software → "AI 소프트웨어"
        ├── ai_semiconductor → "AI 반도체"
        ├── quantum → "양자 컴퓨팅·네트워킹"
        ├── ai_robotics → "AI 로보틱스"
        └── aerospace → "항공우주 방산"
    ↓
all_articles (전체 기사 통합, 총 21개)

4-2. 섹션별 그룹핑

 
sections_map 초기화 (6개 섹션)
    ↓
all_articles 순회
    ↓ category별 분류
sections_map[섹션명] = [기사1, 기사2, 기사3]
    ↓
JSON 직렬화 (간결한 형태)

📋 데이터 구조

 
python
# 각 기사 객체 구조
{
    "category": "섹션명(한글)",
    "headline": "기사 제목",
    "source": "출처명",
    "url": "기사 URL",
    "urlToImage": "이미지 URL",
    "snippet": "기사 내용",
    "date": "발행일시"
}

🤖 STEP 5: AI 분석 및 요약

🎯 목적

OpenAI를 통해 섹션별 기사 요약 및 시장 분석 리포트 생성

📊 데이터 플로우

 
sections_map (JSON 직렬화)
    ↓
OpenAI 프롬프트 구성
    ├── System Message: 역할 및 출력 형식 지정
    └── User Message: 실제 뉴스 데이터 전달
    ↓
OpenAI API 호출 (o4-mini 모델)
    ↓
JSON 응답 파싱
    ├── 성공: 요약 섹션 + 추천 종목
    └── 실패: 원본 기사 + 빈 추천 리스트

🔧 AI 프롬프트 구조

System Message 핵심 내용

  • 역할: "미국 금융 시장 리포터"
  • 작업: 6개 섹션 기사 요약 + 추천 업종·종목 3선
  • 형식: 순수 JSON 객체만 출력
  • 키 구조: date, sections, recommendations

User Message 구성

  • 현재 날짜 명시: target_date
  • 실제 뉴스 데이터: sections_map JSON
  • 출력 요구사항 재강조

📝 응답 파싱 및 오류 처리

 
python
try:
    parsed = json.loads(content)
    found_sections = parsed.get("summary_sections", [])
    found_recommendations = parsed.get("recommendations", [])
except json.JSONDecodeError:
    # 파싱 실패 시 원본 데이터 사용
    found_sections = 원본_sections_map
    found_recommendations = []

💾 STEP 6: 최종 JSON 생성 및 저장

🎯 목적

분석 결과를 구조화된 JSON 파일로 저장

📊 데이터 플로우

 
AI 분석 결과
    ↓
summary_obj 객체 생성
    ├── date: target_datetime
    ├── sections: 요약된 섹션 리스트
    └── recommendations: 추천 업종·종목
    ↓
summaries 디렉터리 생성
    ↓
JSON 파일 저장: us_market_summary_{target_date}.json

📋 최종 JSON 구조

 
json
{
  "date": "2025-05-29 10:30:00",
  "sections": [
    {
      "title": "미국 주식시장 동향",
      "items": [
        {
          "headline": "기사 제목",
          "source": "출처명",
          "url": "기사 URL",
          "urlToImage": "이미지 URL",
          "snippet": "기사 내용",
          "date": "2025-05-29T08:00:00Z"
        }
      ]
    }
  ],
  "recommendations": [
    {
      "sector": "AI 소프트웨어",
      "stocks": ["AAPL", "MSFT", "GOOGL"]
    }
  ]
}

📝 파일 저장 규칙

  • 디렉터리: summaries/
  • 파일명: us_market_summary_{target_date}.json
  • 인코딩: UTF-8
  • 형식: 들여쓰기 2칸으로 가독성 향상

⚠️ 예외 처리 및 오류 대응

🔧 주요 오류 처리 포인트

1. API 호출 실패

 
NewsAPI 응답 오류
    ↓
빈 리스트 반환
    ↓
다음 단계 정상 진행

2. 크롤링 실패

 
URL 접근 오류
    ↓
빈 문자열 반환
    ↓
원본 snippet 유지

3. OpenAI 파싱 실패

 
JSON 파싱 오류
    ↓
경고 메시지 출력
    ↓
원본 sections_map 사용

4. AttributeError 방지

  • 원인: art.get("source", {}).get("name", "")에서 source가 문자열일 때
  • 해결: 섹션별로 데이터 구조 분리 처리

🚀 실행 방법

📋 사전 준비

  1. 설정 파일: efriend_config.yaml에 API 키 설정
     
    yaml
    OPENAI_SEC_KEY: "your-openai-api-key"
    NEWS_API_KEY: "your-news-api-key"
  2. 패키지 설치:
     
    bash
    pip install openai requests beautifulsoup4 PyYAML pandas python-dateutil pytz

🎯 실행 명령

 
bash
python make_summary.py

📊 실행 결과

  • 성공: summaries/us_market_summary_YYYY-MM-DD.json 파일 생성
  • 로그: 각 단계별 진행 상황 출력
  • 오류: 상세한 에러 메시지와 함께 traceback 출력

📈 확장 및 개선 아이디어

🔧 설정 변경 가능 항목

  • 키워드 추가: topic_queries에 새로운 검색어 추가
  • 기사 개수 조정: 상위 3개 → 5개 또는 다른 개수로 변경
  • AI 모델 설정: 토큰 수, 온도 등 파라미터 조절
  • 크롤링 범위: 최대 문자 수 조정

🚀 자동화 방안

  • 스케줄링: Cron Job, AWS Lambda, Kubernetes CronJob
  • 알림 기능: 오류 발생 시 Email/SMS 알림
  • 모니터링: 실행 상태 및 결과 품질 모니터링

📞 문제 해결 가이드

❓ 자주 발생하는 문제

  1. API 키 오류: efriend_config.yaml 파일 확인
  2. 네트워크 오류: 인터넷 연결 및 방화벽 설정 확인
  3. JSON 파싱 실패: OpenAI 응답 로그 확인 후 프롬프트 조정
  4. 파일 저장 실패: summaries 디렉터리 권한 확인

🔍 디버깅 팁

  • 각 단계별 로그 메시지 확인
  • serialized_sections 출력으로 데이터 구조 검증
  • OpenAI 응답 내용 직접 확인
  • 예외 발생 시 traceback 전체 내용 분석

이 메뉴얼은 make_summary.py 프로그램의 전체 데이터 플로우를 단계별로 설명하여, 프로그램의 동작 원리를 쉽게 이해할 수 있도록 구성되었습니다.

위처럼 생성된 json파일은 하기의 웹앱으로 보내집니다. 참조하시기 바랍니다.

https://howardkim.pythonanywhere.com/

 

반응형

댓글()

뉴스요약 시스템 구축

AI주식자동매매|2025. 6. 2. 16:48
반응형

안녕하세요? 드디어 저도 웹사이트를 하나 갖게되었습니다.

https://howardkim.pythonanywhere.com 에 저의 집을 만들었습니다. 

 

gold_stock

 

howardkim.pythonanywhere.com

 

 

내용은 다음과 같습니다.

 

 

 

반응형

댓글()

ImportError: DLL load failed while importing QtWidgets

AI주식자동매매|2024. 10. 12. 15:16
반응형

anaconda 64bit 설치후`
>python -m pip install --upgrade pip

>set CONDA_FORCE_32BIT=1
>conda create -n py38_32 python=3.8
>activate py38_32

>pip install pyqt5

 

 

ImportError: DLL load failed while importing QtWidgets 지정된 모듈을 찾을 수 없습니다.

라는 메세지가 뜰때는 하기 link에서 직접 관련 파일을 다운받습니다.

https://www.riverbankcomputing.com/pypi/simple/pyqt5/

 

Links for pyqt5

 

www.riverbankcomputing.com

저는 kiwoom api 사용하므로 32bit env환경에서 사용하므로 , 32bit용을 다운 받았습니다.

>pip install c:\PyQt5-5.15.12.dev2408131152-cp38-abi3-win32.whl

이렇게 직접 다운받은 파일을 이용해서 설치를 합니다.

그리고, 계속 합니다.

 

>pip install pytz
>pip install numpy pandas requests
>pip install numpy>=1.21.2 pandas>=1.3.0 requests>=2.31

>pip install numpy

>pip install --user pandas==1.5.3 

pandas2.0은 matplotlib 최신버젼과 호환이 되지 않아서 지정된 버젼으로 설치합니다.

>pip install c:\TA_Lib-0.4.24-cp38-cp38-win32.whl

>pip install c:\TA_Lib-0.4.24-cp37-cp37m-win_amd64.whl

 

>pip install mpl_finance
# >pip install pycurl  #
>pip install c:\pycurl-7.45.1-cp38-cp38-win32.whl
  
# Successfully installed PyQt5-5.15.9
>pip install PyQt5Singleton
>pip install slacker
>pip install telegram

>conda install -c conda-forge finance-datareader


#>pip uninstall python-telegram-bot telegram -y
>pip install python-telegram-bot
>pip install python-telegram-bot --upgrade
>pip install python-telegram-bot==13.3 # 20.0a0버젼부터는 dispatcher를 더이상 사용불가합니다. 계속사용하려면13.3을 설치합니다.
>pip install holidays
>pip install gtts
>pip install pyglet==1.5 #2.0이상부터는 python 3.8 이상 사용해야 한다.
>pip install mplfinance #ERROR: Could not build wheels for pillow which use PEP 517 and cannot be installed directly
>pip install lxml
>pip install https://github.com/pyinstaller/pyinstaller/archive/develop.zip
>pip install yfinance
>pip install pandas_datareader
>pip install bs4
>pip install matplotlib 대신 >conda install matplotlib 사용해야 한

>pip install Pillow==9.5.0 #Requirement already satisfied: Pillow==9.5.0 in c:\users\howto\appdata\roaming\python\python38\site-packages (9.5.0)
>pip install pyautogui
>pip install selenium
>pip install scikit-learn #scikit-learn이란 python을 대표하는 머신러닝 라이브러리이다. '사이킷런'이라고 부르기도 한다
>pip install PyYAML #yaml파일의 내용을 딕셔너리로 만들어준다.

 

>conda deactivate

 

여기서부터는 64비트 env환경에서 사용할 환경설정을 시작합니다.
>set CONDA_FORCE_64BIT=1
>conda create -n py38_64 python=3.8 
>activate py38_64

 

>pip install numpy pandas

> pip install pyqt5

> pip install slacker

>pip install telegram

> pip install mplfinance

> pip install pyupbit

>pip install pybithumb

> pip install torch torchvision

> pip install torch torchvision

> pip uninstall python-telegram-bot telegram -y
>pip install python-telegram-bot

> pip install yfinance

> pip install sklearn

> pip install stable_baselines3

> pip install bayes_opt

> pip install bayesian-optimization # bayes_opt 패키지는 **bayesian-optimization**으로 설치해야 합니다.

> pip install gym

> pip install openai

> pip install python-telegram-bot

> pip install python-telegram-bot --upgrade

 


># pip install torch===1.3.1 torchvision===0.4.2 -f https://download.pytorch.org/whl/torch_stable.html #No matching distribution found for torch===1.3.1

>pip install holidays
>pip install gtts
>pip install pyglet #pyglet 2.0.1 requires Python 3.8 or newer.
>
>pip install lxml
>pip install https://github.com/pyinstaller/pyinstaller/archive/develop.zip
>pip install yfinance
>pip install pandas_datareader
>pip install gym==0.25.2
>pip install pygame
>pip install pytz
>pip install -U finance-datareader
>CUDA download
>pip install -U scikit-learn or conda install scikit-learn
>Visual Studio Downloadde
>pip install sklearn 

>set CONDA_FORCE_64BIT=1
>conda create -n py39_64 python=3.9 anaconda
>activate py39_64

>pip install torch
#최신버전의 tensrflow를 설치한다.
>pip install tensorflow
or 
>py -m pip install tensorflow
or
>python -m pip install --user --upgrade pip
Collecting pip
  Using cached pip-20.1.1-py2.py3-none-any.whl (1.5 MB)
Installing collected packages: pip
  WARNING: The scripts pip.exe, pip3.7.exe and pip3.exe are installed in 'C:\Users\howto\AppData\Roaming\Python\Python37\Scripts' which is not on PATH.
  Consider adding this directory to PATH or, if you prefer to suppress this warning, use --no-warn-script-location.
Successfully installed pip-20.1.1

PATH에 추가해도 안됨..

(env 삭제)
>conda env remove -n ENV_NAME



또는
If you are using python-3

>py -m pip install --upgrade pip
>py -m pip install tensorflow

> pip install --upgrade tensorflow

$ pip install numpy scipy
$ pip install scikit-learn
$ pip install pillow
$ pip install h5py
talling Keras with TensorFlow backendShell
$ pip install keras
$ workon keras_tf

>pip install pyinstaller

>pyinstaller --version
3.6
# PyQt5를 포함하여 main.exe 실행파일 만들기
>pyinstaller --windowed --onefile main.py
  exe실행시 ("Fatal error detected","Failed to execute script main") 메세지 뜸.
그래서, 이번엔..
>pyinstaller --onefile main.py

다시..
>pyinstaller myfile.py --upx-dir=..\upx391w -y --onefile

=> cannot import name 'pywrap_tensorflow' from 'tensorflow_core.python'


결국, 
"if you are using anaconda, python 3.7 is installed by default, so you have to downgrade it to 3.6:"
그래서..
>conda install python=3.6
실행함...
그리고, 다시..
# Requires the latest pip
>pip install --upgrade pip

# Current stable release for CPU and GPU
>pip install --ignore-installed --upgrade tensorflow

# Or try the preview build (unstable)
>pip install tf-nightly

반응형

댓글()

GPT 4o Vision 활용하기(3)

AI주식자동매매|2024. 10. 6. 14:36
반응형

안녕하세요? 

이번에는  ChatGPT Vision을 어떤 곳에서 활용할 수 있을까를 생각해 봤습니다.

이 글을 읽으신 분들도 한번 같이 생각해 봐 주시고, 의견 달아주시면 정말 감사하겠습니다.

 

1) 주식 차트정보를 보여주고, 이 주식 매수해도 될지 ChtGPT에게 물어보기

    - 제가 지금 API를 통해서 구현하면서 얼마나 정확성이 있는지 테스트 해보고 있는 방법이죠.

      GPT 4o Vision 활용하기(1)을 참조해 주세요.

 

2) 인물 사진을 보여주고, 누구인지, 어디사는 사람인지, 한국인인지 일본인지, 중국인지 등 물어볼 수 있겠죠?

 

3) 식물, 동물 사진 보여주고, 식물이름이나, 동물이름, 해조류 이름 등 맞추기

 

4) 분해되어 있거나, 아직 조립하지 않은 물건을 어떻게 조립하면 될지 물어볼수도 있겠죠?

 

5) 생산제품 외관사진을 보여주고 불량인지 아닌지 판별해 달라고 할 수 도 있겠죠?

 

6) 두장의 사진을 비교해서 보여주고, 어떤 문제가 있는지 분석요청도 할 수 있겠죠?

 

7) 어떤 사고현장 사진을 보여주고, 현 상황을 설명하게 하고, 119나 112에 전화하는 기능과 연결할 수도 있겠죠?

 

이 밖에 다양하게 인공지능 생성형 AI Vision 기능을 통해서 할 수 있는 일들이 무궁무진할 것 같긴합니다.

여러분들은 어떤 곳에서 사용될 수 있을거라고 생각하시나요?

 

반응형

댓글()

GPT 4o Vision 활용하기(2)

AI주식자동매매|2024. 10. 6. 14:25
반응형

이번에는 ChatGPT Vision을 사용할 경우, 각 버젼별 비용을 알아볼거에요.

 

1) GPT-4o( GPT-4o-2024-05-13 )

    1일 사용 token 2,292,425 token(input&output)

    1일 사용 Cost 11.52$

    ------------------------------

     1 token당 약 0.006784원(Won) => 1회당 약 300 token 사용한다고 할때, 1회 API요청시 약 2원이 사용됨.

9월25일 Activity Tokens
9월25일 Costs

2) GPT-4o-mini GPT-4o-2024-05-13

    1일 사용 token 146,851,547 token(input&output)

    1일 사용 Cost 22.04$

     ------------------------------

     1 token당 약 0.0002026원 => 1회당 약 300 token 사용한다고 할때, 1회 API요청시 약 0.06원이 사용됨.

9/25일 Activity Tokens

   

9월25일 Costs

 

결국, GPT-4o는 GPT-4o-mini보다 약 33배 비싸다고 할 수 있겠네요.

 

이용에 참조하세요.

반응형

댓글()

GPT 4o Vision 활용하기

카테고리 없음|2024. 9. 25. 06:34
반응형

이미지를 호출하여 encode 하고, openapi 호출하기

# 이미지를 저장할 폴더 이름
folder_name = 'image'
# 저장할 파일의 경로를 설정. 여기서는 'image/파일명.jpg' 형식을 사용합니다.
image_path = os.path.join(folder_name, stockCode + "_" + current_date_str + ".jpg")
# Getting the base64 string
base64_image = self.encode_image(image_path=image_path)
description = self.describe_image(api_key=self.openai_secret_key, base64_image=base64_image)
# print(f"이미지 설명: {description}")
if description is None:
    # text = "gpt-4o-mini 검증 실패"
    # self.ui.pteLog.appendPlainText("%s(%s) %s" % (stockName, stockCode, text))
    market_trand = 0
elif 'No' in description:  # Case-insensitive check for 'No'
    text = "%s(%s) gpt-4o vision says %s" % (stockName, stockCode, description)
    self.ui.pteLog.appendPlainText(text)
    market_trand = 0
elif 'Yes' in description:  # Case-insensitive check for 'Yes'
    text = "%s(%s) gpt-4o vision says %s" % (stockName, stockCode, description)
    self.ui.pteLog.appendPlainText(text)
    market_trand = 5
else:
    # text = "%s(%s) gpt-4o vision says %s" % (stockName, stockCode, description)
    # self.ui.pteLog.appendPlainText(text)
    market_trand = 0

 

사용된 함수들

# Function to encode the image
def encode_image(self, image_path=''):
    with open(image_path, "rb") as image_file:
        return base64.b64encode(image_file.read()).decode('utf-8')

def describe_image(self, api_key='', base64_image=''):  # GPT-4 Vision 모델용
    """
    GPT-4 Vision 모델을 사용하여 이미지를 설명하는 함수
    """
    # print("GPT-4 Vision 모델을 사용하여 이미지를 설명하는 함수")
    try:
        headers = {
            "Content-Type": "application/json",
            "Authorization": f"Bearer {api_key}"
        }

        payload = {
            "model": "gpt-4o",  # "model": "gpt-4o-mini",
            "messages": [
                {
                    "role": "user",
                    "content": [
                        {
                            "type": "text",
                            "text": "If the price is holding support and showing signs of upward momentum, it might be a good time to buy, right? Look at the left-side day chart and right-side 5-minute chart. After closing inspection of the 5-minute chart, Please say 'Yes' if you sure it is fully and clearly transitioned into an upward trend momentum. if not, say No."
                        },
                        {
                            "type": "image_url",
                            "image_url": {
                                "url": f"data:image/jpeg;base64,{base64_image}"
                            }
                        }
                    ]
                }
            ],
            "max_tokens": 300
        }
    except Exception as e:
        print("GPT-4 Vision 모델을 사용하여 이미지를 설명: %s" % e)
        return None
    response = requests.post("https://api.openai.com/v1/chat/completions", headers=headers, json=payload)
    # print(response.json())
    # Parse the JSON response
    response_data = response.json()
    # Print only the 'choices' part
    choices = response_data.get('choices', [])
    if choices:
        content = choices[0]['message']['content']
        # print(content)
        return content
    else:
        print("No content found.")
        return None

 

Telegram Bot을 통해 결과 확인.

반응형

댓글()

강화학습 PPO 모델을 이용한 자동매매 2

AI주식자동매매|2024. 8. 9. 07:28
반응형

import numpy as np
import pandas as pd
import gym
from gym import spaces
from stable_baselines3 import PPO
from stable_baselines3.common.evaluation import evaluate_policy
from sklearn.model_selection import train_test_split
from datetime import datetime
from pytz import timezone
from sklearn.model_selection import ParameterGrid
import warnings

# 특정 경고 메시지 무시
warnings.filterwarnings("ignore", category=UserWarning)

class TradingEnv(gym.Env):
    def __init__(self, df):
        super(TradingEnv, self).__init__()
        self.df = df
        self.current_step = 0
        self.df_numeric = self._convert_to_numeric(self.df)
        self.action_space = spaces.Discrete(2)  # Buy or Hold

        self.observation_space = spaces.Box(low=0, high=1, shape=(self.df_numeric.shape[1],), dtype=np.float32)

        self.initial_balance = 10000
        self.balance = self.initial_balance
        self.net_worth = self.initial_balance
        self.max_net_worth = self.initial_balance
        self.shares_held = 0
        self.current_price = self.df.iloc[self.current_step]['close']  # 현재 스텝의 가격으로 초기화
        self.price_history = self.df['close'].tolist()  # 전체 가격 데이터를 리스트로 저장

    def _convert_to_numeric(self, df):
        df_numeric = df.copy()
        df_numeric = df_numeric.filter(regex='^m_')
        df_numeric.reset_index(drop=True, inplace=True)  # 인덱스를 드롭하고 리셋
        for column in df_numeric.columns:
            df_numeric[column] = pd.to_numeric(df_numeric[column], errors='coerce')
        df_numeric.fillna(0, inplace=True)
        return df_numeric

    def reset(self):
        self.balance = self.initial_balance
        self.net_worth = self.initial_balance
        self.max_net_worth = self.initial_balance
        self.shares_held = 0
        self.current_step = 0
        self.current_price = self.df.iloc[self.current_step]['close']  # 리셋 시 현재 가격 초기화
        return self._next_observation()

    def _next_observation(self):
        obs = self.df_numeric.iloc[self.current_step].values
        obs_max = obs.max() if obs.max() != 0 else 1  # Prevent division by zero
        obs = obs / obs_max
        return obs

    def step(self, action):
        self.current_step += 1
        self.current_price = self.df.iloc[self.current_step]['close']  # 매 스텝마다 현재 가격 업데이트
        self.low_price = self.df.iloc[self.current_step]['low']  # 매 스텝마다 현재 가격 업데이트
        self.current_time = self.df.index[self.current_step]  # 매 스텝마다 현재 가격 업데이트

        if action == 1:  # Buy
            self.shares_held += self.balance / self.current_price
            self.balance = 0
        elif action == 0:  # Hold
            pass

        self.net_worth = self.balance + self.shares_held * self.current_price
        self.max_net_worth = max(self.max_net_worth, self.net_worth)

        # 1시간 후 가격 변동을 확인하여 보상을 계산
        reward = self.calculate_reward(action)
        done = self.current_step >= len(self.df) - 1

        obs = self._next_observation()
        return obs, reward, done, {}

    def calculate_reward(self, action):
        '''
        현재 가격에서 시작하여 다음 12 스텝 동안의 가격을 모두 체크하며, 그 중 하나라도 5% 이상 상승한 경우 보상으로 1을 반환합니다. 1시간 동안 5% 이상 상승한 적이 없다면 보상으로 0을 반환합니다.
        즉, buy 의견을 제시한것이 잘했는지를 평가할때, reward 보상으로 학습을 시킨다.
        '''
        end_step = min(self.current_step + 12, len(self.df) - 1)  # 1시간 = 12 steps (assuming 5-minute intervals)
        reward = 0

        if action == 1:  # Buy 액션일 경우에만 보상 계산
            for step in range(1, end_step - self.current_step + 1):
                future_price = self.price_history[self.current_step + step]
                price_increase = (future_price - self.current_price) / self.current_price
                if (step - self.current_step) <= 5:
                    if future_price < self.low_price:  # 5봉 이내(30분이내) 현재가보다 하락하고 있으면, reward 없음.
                        break
                if price_increase >= 0.05:  # 5% 이상 상승
                    print("%s self.current_step:%s" % (self.current_time, self.current_step))
                    print("for range step:%s" % (step))
                    print("future_price:%s" % (self.price_history[self.current_step + step]))
                    print("price_increase:%s" % ((future_price - self.current_price) / self.current_price))
                    print("reward = 1")
                    reward = 1
                    break
        return reward  # 1시간 동안 5% 이상 상승하지 않음

def optimize_ppo(data, param_grid, model_path="ppo_trading_model"):
    env = TradingEnv(data)
    best_model = None
    best_reward = -float('inf')
    
    for params in ParameterGrid(param_grid):
        model = PPO('MlpPolicy', env, verbose=1, **params)
        model.learn(total_timesteps=10000)
        total_rewards = evaluate_model(model, data)
        if total_rewards > best_reward:
            best_reward = total_rewards
            best_model = model
            best_model.save(model_path)
    
    return best_model

def train_model(data, model_path="ppo_trading_model"):
    env = TradingEnv(data)
    try:
        model = PPO.load(model_path)
        print("Model loaded successfully. Continuing training...")
    except:
        model = PPO('MlpPolicy', env, verbose=1)
        print("New model initialized.")

    model.set_env(env)
    param_grid = {
        'n_steps': [128, 256, 512],
        'learning_rate': [1e-3, 1e-4, 1e-5],
        'batch_size': [128, 256],  # 변경된 부분: 128의 배수로 설정
    }
    best_model = optimize_ppo(data, param_grid, model_path)
    best_model.learn(total_timesteps=10000)
    best_model.save(model_path)
    return best_model


def load_model(model_path="ppo_trading_model"):
    return PPO.load(model_path)


def evaluate_model(model, data):
    env = TradingEnv(data)
    obs = env.reset()
    total_rewards = 0
    done = False
    while not done:
        action, _states = model.predict(obs)
        obs, reward, done, _ = env.step(action)
        total_rewards += reward
    return total_rewards


def main():
    ticker = 'XEM'
    chart_intervals = 'minute5'
    current_time = pd.to_datetime(datetime.now(timezone('Asia/Seoul'))).strftime("%Y-%m-%d %H:%M:%S")
    chart_data = save_db_market_infos(ticker=ticker, chart_intervals=chart_intervals, current_time=current_time)
    chart_data.set_index('time', inplace=True)
    strategy_data = get_strategy_mst_data()

    if chart_data is not None:
        strategy_chart_data = calculate_indicators(chart_data, ticker)
        strategy_chart_data_df = pd.DataFrame([strategy_chart_data])

        train_data, test_data = train_test_split(chart_data, test_size=0.2, shuffle=False)

        model = train_model(train_data)

        total_rewards = evaluate_model(model, test_data)
        print(f"Total Rewards: {total_rewards}")
        if isinstance(strategy_chart_data_df, pd.DataFrame):
            obs = strategy_chart_data_df.values.flatten().astype(np.float32)
            obs = np.expand_dims(obs, axis=0)
            action, _states = model.predict(obs)
            print("Buy Signal:", "Yes" if action == 1 else "No")
        else:
            print("Error: strategy_chart_data is not a DataFrame")
    else:
        print("Error: chart_data is None")

if __name__ == "__main__":
    main()

반응형

댓글()

코인/주식 자동매수에 머신러닝 강화학습 PPO적용하기 1

AI주식자동매매|2024. 8. 9. 07:13
반응형

PPO (Proximal Policy Optimization)와 DQN (Deep Q-Network)은 강화 학습에서 널리 사용되는 두 가지 알고리즘입니다. 이 두 가지는 각각의 특성과 장단점이 있으며, 특정 상황에 따라 더 적합한 알고리즘이 달라질 수 있습니다.

PPO (Proximal Policy Optimization)

특징:

  • 정책 기반 (Policy-based) 알고리즘: PPO는 정책 기반 방법론을 따르며, 이를 통해 직접적으로 행동 정책을 업데이트합니다.
  • 클립핑: PPO는 정책 갱신 시 클리핑(clipping)을 사용하여 큰 갱신을 방지합니다. 이로 인해 학습 과정에서 안정성을 확보할 수 있습니다.
  • 샘플 효율성: PPO는 여러 번의 에포크 동안 샘플을 다시 사용하므로, 샘플 효율성이 높습니다.

장점:

  • 안정성: PPO는 클리핑을 통해 정책 갱신을 안정적으로 수행합니다.
  • 샘플 재사용: PPO는 여러 번의 업데이트 동안 샘플을 재사용할 수 있어, 데이터 효율성이 높습니다.
  • 연속적 액션 공간: PPO는 연속적이고 다차원적인 액션 공간에서 잘 동작합니다.

단점:

  • 복잡성: PPO는 상대적으로 복잡한 알고리즘이어서 구현과 조정이 어려울 수 있습니다.
  • 트레이닝 시간: PPO는 많은 트레이닝 시간을 필요로 할 수 있습니다.

DQN (Deep Q-Network)

특징:

  • 값 기반 (Value-based) 알고리즘: DQN은 Q-러닝을 심층 신경망으로 확장하여 상태-액션 값 함수를 추정합니다.
  • 에피소드 학습: DQN은 에피소드 단위로 학습을 수행하며, 학습에 사용되는 경험은 리플레이 버퍼에서 샘플링됩니다.
  • 이산적 액션 공간: DQN은 이산적 액션 공간에서 동작하며, 연속적 액션 공간에 대해 사용하기 어렵습니다.

장점:

  • 상대적으로 단순: DQN은 비교적 이해하고 구현하기 쉬운 알고리즘입니다.
  • 이산적 액션 공간: 이산적 액션 공간을 다루는 데 적합하며, 간단한 환경에서 매우 효과적입니다.
  • 연속된 상태에서 학습 가능: DQN은 특정 환경에서 좋은 성능을 보일 수 있으며, 환경이 안정적일 때 강력한 결과를 낼 수 있습니다.

단점:

  • 연속적 액션 공간에서의 한계: DQN은 연속적 액션 공간에 적용하기 어려우며, 이를 다루기 위해 추가적인 기법이 필요합니다.
  • 샘플 비효율성: DQN은 PPO에 비해 샘플 효율성이 낮으며, 많은 데이터를 필요로 할 수 있습니다.
  • 불안정성: 큰 상태 공간이나 복잡한 환경에서는 학습이 불안정할 수 있습니다.

일반적인 사용 사례:

  • PPO: 연속적 액션 공간, 복잡한 환경, 로봇 제어, 자율주행 등에서 많이 사용됩니다.
  • DQN: 이산적 액션 공간, 비교적 단순한 환경, Atari 게임 등에서 많이 사용됩니다.

요약:

  • PPO는 복잡한 환경에서 안정적이고 샘플 효율성이 높은 강화 학습을 원할 때 사용됩니다.
  • DQN은 단순하고 이산적인 액션 공간을 가진 환경에서 사용하기 쉬운 알고리즘입니다.

각각의 장단점을 고려하여, 특정 문제에 맞는 알고리즘을 선택하는 것이 중요합니다.

반응형

댓글()