3. chatGPT 연동하기(투자 판단)

2025. 2. 8. 19:50·프로젝트/coin-trading
목차
  1. □ 업비트 API에서 차트 추출 API(json타입으로 추출하기)
  2. □ GPT에 차트 전달 및 투자의견 받아오기
  3. □ 매매 API에 적용하기
  4. □ 앞으로의 계획

□ 업비트 API에서 차트 추출 API(json타입으로 추출하기)

private static String candleExtract() throws IOException {
        // 업비트 차트 전달 15일치 일봉데이터 가져오기
        OkHttpClient client = new OkHttpClient();

        Request request = new Request.Builder()
                .url("https://api.upbit.com/v1/candles/days?market=KRW-ETH&count=15")
                .get()
                .addHeader("accept", "application/json")
                .build();

        // try-with-resources 구문을 사용하여 자동으로 닫히도록 함
        try (Response response = client.newCall(request).execute()) {
            String jsonResponse = response.body().string();

            // Jackson을 이용한 JSON 파싱
            ObjectMapper objectMapper = new ObjectMapper();
            UpbitCandle[] candles = objectMapper.readValue(jsonResponse, UpbitCandle[].class);
            SimpleCandleDTO[] filteredCandles = Arrays.stream(candles)
                    .map(candle -> new SimpleCandleDTO(candle.getCandleDateTimeKst(), candle.getOpeningPrice(), candle.getHighPrice(), candle.getLowPrice(), candle.getTradePrice(), candle.getCandleAccTradeVolume()))
                    .toArray(SimpleCandleDTO[]::new);

            return objectMapper.writeValueAsString(filteredCandles);
        }
    }
  • url의 {일봉, 주봉 등}?market={종목}&count={차트수}의미

- 차트 DTO


package coin.cointrading.dto;

import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
public class UpbitCandle {
    private String market;

    @JsonProperty("candle_date_time_utc")
    private String candleDateTimeUtc;

    @JsonProperty("candle_date_time_kst")
    private String candleDateTimeKst;

    @JsonProperty("opening_price")
    private double openingPrice;

    @JsonProperty("high_price")
    private double highPrice;

    @JsonProperty("low_price")
    private double lowPrice;

    @JsonProperty("trade_price")
    private double tradePrice;

    @JsonProperty("prev_closing_price")
    private double prevClosingPrice;

    @JsonProperty("change_price")
    private double changePrice;

    @JsonProperty("change_rate")
    private double changeRate;

    @JsonProperty("converted_trade_price")
    private double convertedTradePrice;

    private long timestamp;

    @JsonProperty("candle_acc_trade_price")
    private double candleAccTradePrice;

    @JsonProperty("candle_acc_trade_volume")
    private double candleAccTradeVolume;

    @JsonProperty("first_day_of_period")
    private String firstDayOfPeriod;
}

 

- 차트에서 필요한 데이터만 추출하는 DTO


package coin.cointrading.dto;

import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Getter;
import lombok.RequiredArgsConstructor;

@Getter
@RequiredArgsConstructor
public class SimpleCandleDTO {
    @JsonProperty("candle_date_time_kst")
    private final String candleDateTimeKst;

    @JsonProperty("opening_price")
    private final double openingPrice;

    @JsonProperty("high_price")
    private final double highPrice;

    @JsonProperty("low_price")
    private final double lowPrice;

    @JsonProperty("trade_price")
    private final double tradePrice;

    @JsonProperty("candle_acc_trade_volume")
    private final double candleAccTradeVolume;
}

 

※ 왜 try-with-resources를 사용할까? - gpt검색

Response 객체는 네트워크 연결을 사용하기 때문에 사용이 끝난 후 반드시 닫아야 합니다.
기본적으로 Response 객체의 body() 메서드를 사용하여 응답 데이터를 읽으면, 내부 스트림이 열려 있기 때문에 이를 닫지 않으면 메모리 누수가 발생할 수 있습니다.

이를 해결하려면 response.close()를 명시적으로 호출해야 하지만, try-with-resources를 사용하면 try 블록을 빠져나갈 때 자동으로 close()가 호출됩니다.

 

□ GPT에 차트 전달 및 투자의견 받아오기

- openai API에 접속해서 key 및 결재수단 등록

https://platform.openai.com/

- Playground로가서 System message 작성하기(ai의 성향, 응답타입 등)

- gpt연동 코드(openaiKey는 서비스 필드로 선언)

public String aiDecision() throws IOException {
        final String gptUrl = "https://api.openai.com/v1/chat/completions";

        OkHttpClient client = new OkHttpClient();
        ObjectMapper objectMapper = new ObjectMapper();

        String extractedData = candleExtract();  // 이 데이터는 JSON 배열 형태입니다.

        // extractedData를 안전하게 JSON으로 포맷
        ObjectNode requestBodyNode = objectMapper.createObjectNode();
        requestBodyNode.put("model", "gpt-3.5-turbo");
        requestBodyNode.put("temperature", 1);
        requestBodyNode.put("max_tokens", 2048);
        requestBodyNode.put("top_p", 1);
        requestBodyNode.put("frequency_penalty", 0);
        requestBodyNode.put("presence_penalty", 0);

        ArrayNode messages = requestBodyNode.putArray("messages");
        ObjectNode systemMessage = messages.addObject();
        systemMessage.put("role", "system");
        systemMessage.put("content", "You're a Coin Invest expert. Tell me if I should buy, sell, or hold based on the chart data provided. Respond in JSON format. Answer in Korean.\n\nResponse Example:\n{\"decision\": \"buy\", \"reason\": \"기술적인 이유 설명\"}\n{\"decision\": \"sell\", \"reason\": \"기술적인 이유 설명\"}\n{\"decision\": \"hold\", \"reason\": \"기술적인 이유 설명\"}");


        ObjectNode userMessage = messages.addObject();
        userMessage.put("role", "user");
        userMessage.put("content", extractedData);  // 그대로 이 데이터를 JSON 형식으로 삽입

        // HTTP 요청 생성
        Request request = new Request.Builder()
                .url(gptUrl)
                .addHeader("Authorization", "Bearer " + openAiKey)
                .addHeader("Content-Type", "application/json")
                .post(RequestBody.create(requestBodyNode.toString(), MediaType.get("application/json")))
                .build();

        // 요청 실행 및 응답 처리
        try (Response response = client.newCall(request).execute()) {
            if (!response.isSuccessful()) {
                throw new IOException("Unexpected response code: " + response.code() + " " + response.body().string());
            }

            // JSON 응답 파싱
            JsonNode jsonResponse = objectMapper.readTree(response.body().string());

            // 필요한 데이터 추출
            JsonNode choices = jsonResponse.path("choices");
            if (choices.isArray() && !choices.isEmpty()) {
                JsonNode decision = choices.get(0).path("message").path("content");
                return decision.asText();
            } else {
                throw new IOException("No choices in the response.");
            }
        }
    }

 

□ 매매 API에 적용하기

public OrderResponse orderCoin() throws IOException, NoSuchAlgorithmException {
        List<AccountResponse> account = getAccount();

        AccountResponse KRW = new AccountResponse();
        AccountResponse ETH = new AccountResponse();

        for (AccountResponse accountResponse : account) {
            if (accountResponse.getCurrency().equals("KRW")) KRW = accountResponse;
            else if (accountResponse.getCurrency().equals("ETH")) ETH = accountResponse;
        }

        ObjectMapper objectMapper = new ObjectMapper();
        JsonNode jsonNode = objectMapper.readTree(aiDecision());

        String decision = jsonNode.path("decision").asText();
        String side;
        if (decision.equals("buy")) {
            side = "bid";
        } else if (decision.equals("sell")) {
            side = "ask";
        } else {
            return null;
        }

        double balance = Math.floor(Double.parseDouble(KRW.getBalance()) * 0.9995);
        String price = Double.toString(balance);
        String volume = ETH.getBalance();
        String ord_type = side.equals("bid") ? "price" : "market";

        HashMap<String, String> params = new HashMap<>();
        params.put("market", "KRW-ETH");
        params.put("side", side);
        params.put("ord_type", ord_type);

        if (side.equals("bid")) {
            params.put("price", price);
        } else {
            params.put("volume", volume);
        }

        String orderUrl = serverUrl + "/v1/orders";
        HttpHeaders headers = new HttpHeaders();
        headers.set("Content-Type", "application/json");
        headers.set("Authorization", jwtTokenProvider.createOrderToken(params));
        HttpEntity<String> entity = new HttpEntity<>(new Gson().toJson(params), headers);

        return restTemplate.exchange(
                orderUrl,
                HttpMethod.POST,
                entity,
                new ParameterizedTypeReference<OrderResponse>() {
                }).getBody();
    }
  • 계좌 정보를 불러오기
  • GPT투자의견을 받아오기 GPT는 투자의견을 buy, sell, hold로 판단해줌
  • 넘어온 내용으로 buy면 모든 잔액을 사용하여 매수(매수 시 수수료 반영하여 계산)
  • sell이면 모든 코인 잔고를 매도

□ 앞으로의 계획

  • gpt의견 api를 얼마나 자주 호출 할 것인가(api 호출 비용 고려)
  • 투자전략 수정고민(변동성 돌파 전략)

 

'프로젝트 > coin-trading' 카테고리의 다른 글

5. EC2 프로그램 동작중... 앞으로의 개선방향  (0) 2025.02.18
4. 투자전략 변경 및 EC2 배포  (0) 2025.02.10
2. 업비트 매매 API 적용  (0) 2025.02.07
1. 업비트 API 적용해보기  (1) 2025.02.05
0. 프로젝트 설계  (0) 2025.02.05
  1. □ 업비트 API에서 차트 추출 API(json타입으로 추출하기)
  2. □ GPT에 차트 전달 및 투자의견 받아오기
  3. □ 매매 API에 적용하기
  4. □ 앞으로의 계획
'프로젝트/coin-trading' 카테고리의 다른 글
  • 5. EC2 프로그램 동작중... 앞으로의 개선방향
  • 4. 투자전략 변경 및 EC2 배포
  • 2. 업비트 매매 API 적용
  • 1. 업비트 API 적용해보기
DJ.Kang
DJ.Kang
백엔드 개발 기록 블로그
  • DJ.Kang
    DJ Hello World
    DJ.Kang
  • 전체
    오늘
    어제
    • 분류 전체보기
      • 이론공부
      • 시스템설계
      • Java & Spring
        • TIL
        • 트러블슈팅
        • 고도화
        • 알고리즘
        • 코딩테스트
        • Java
        • Spring
        • Thymeleaf
      • 프로젝트
        • coin-trading
        • 트러블슈팅
      • Docker
      • DB
      • AWS
      • CI-CD
      • 웹
      • git & github
      • 구인공고분석
  • 블로그 메뉴

    • 홈
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    java 에라토스테네스의 체
    java arrays.copyofrnage()
    개발로드맵
    java two-pointer
    java 세수의합
    데이터 크기
    java 제어자
    java 멤버
    프로그래머스 java 기초트레이닝
    Java 생성자
    java 유클리드 호제법
    java기초
    java super
    java 메서드
    프로그래머스 java 기초 트레이닝
    데이터 타입
    java enhance switch
    Java this
    자료구조
    java
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.1
DJ.Kang
3. chatGPT 연동하기(투자 판단)
상단으로

티스토리툴바

단축키

내 블로그

내 블로그 - 관리자 홈 전환
Q
Q
새 글 쓰기
W
W

블로그 게시글

글 수정 (권한 있는 경우)
E
E
댓글 영역으로 이동
C
C

모든 영역

이 페이지의 URL 복사
S
S
맨 위로 이동
T
T
티스토리 홈 이동
H
H
단축키 안내
Shift + /
⇧ + /

* 단축키는 한글/영문 대소문자로 이용 가능하며, 티스토리 기본 도메인에서만 동작합니다.