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

2025. 2. 8. 19:50·프로젝트/coin-trading

□ 업비트 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
'프로젝트/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 super
    java two-pointer
    java 제어자
    프로그래머스 java 기초 트레이닝
    Java 생성자
    java기초
    java 세수의합
    java
    java 유클리드 호제법
    java 에라토스테네스의 체
    java enhance switch
    Java this
    프로그래머스 java 기초트레이닝
    자료구조
    java arrays.copyofrnage()
    데이터 크기
    java 메서드
    데이터 타입
  • 최근 댓글

  • 최근 글

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

티스토리툴바