□ 업비트 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
- 차트에서 필요한 데이터만 추출하는 DTO
※ 왜 try-with-resources를 사용할까? - gpt검색
Response 객체는 네트워크 연결을 사용하기 때문에 사용이 끝난 후 반드시 닫아야 합니다.
기본적으로 Response 객체의 body() 메서드를 사용하여 응답 데이터를 읽으면, 내부 스트림이 열려 있기 때문에 이를 닫지 않으면 메모리 누수가 발생할 수 있습니다.
이를 해결하려면 response.close()를 명시적으로 호출해야 하지만, try-with-resources를 사용하면 try 블록을 빠져나갈 때 자동으로 close()가 호출됩니다.
□ GPT에 차트 전달 및 투자의견 받아오기
- openai API에 접속해서 key 및 결재수단 등록
- 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' 카테고리의 다른 글
4. 투자전략 변경 및 EC2 배포 (0) | 2025.02.10 |
---|---|
2. 업비트 매매 API 적용 (0) | 2025.02.07 |
1. 업비트 API 적용해보기 (1) | 2025.02.05 |
0. 프로젝트 설계 (0) | 2025.02.05 |