본문 바로가기
[IT] Spring Boot (JAVA)/[웹서비스] 비트코인 자동매매

비트코인 거래소 API를 활용한 비트코인 나만의 웹서비스 개발(2)

by 오리엔탈킴 2021. 12. 3.

안녕하세요, 오리엔탈 킴입니다.

 

비트코인 거래소 빗썸 API를 활용한 비트코인 자동매매 + 자체 웹서비스 (JAVA+Spring Boot) 2번째 포스팅으로 지난 사전 설정(https://kim-oriental.tistory.com/4)에 이어서 본격적인 개발을 진행하겠습니다.

이번 포스팅에는 우선 빗썸 API를 활용하여, 코인의 가격 정보를 가져와서 저장하고 저장된 가격정보를 웹에서 보여주는 간단하고 심플한 나만의 코인 웹서비스를 만드는 것을 목표로 하겠습니다.

 

최대한 심플하고 빠르게 구현할 수 있는 아키텍처 구성을 할 예정입니다. 지난 포스팅(https://kim-oriental.tistory.com/4)에서 프로젝트 생성 및 Dependency 추가한 것과 같이, JAVA Spring Boot 기반의 웹 서비스로 구현을 할 것이고, DB는 라이트 한 H2 DB + JPA로 구성을 할 것이며, FrontEnd 뷰 템플릿은 Thymeleaf를 이용하여 개발할 예정입니다.

 

이번 글에서 구현하고자 하는 서비스의 간단한 기능은 아래와 같습니다. 

 

  • 빗썸 API를 활용하여, 내가 지정한 코인들의 가격과 거래량 값을 10분에 한 번씩 가져와 DB에 저장한다.
  • 웹 페이지에서 코인 별로 저장된 데이터를 보여준다. (추가로 간단한 추세를 보기 위해 그래프를 그려준다)

결국 나만의 가격 DB를 만드는 것인데, 코인 가격 정보를 주기적으로 거래소 API에 요청을 하여 나의 DB에 저장을 해야 그 데이터를 바탕으로 자동으로 매수/매도를 할지 판단하는 백데이터가 되기 때문에 해당 기능을 처음으로 구현할 예정입니다. 단, 제가 금융지식이 별로 없기 때문에 단순한 데이터들만 관리를 하며 프로그램을 구현하는데 집중하도록 하겠습니다.

 

먼저 전체 구현된 메인 페이지는 아래와 같습니다. 아래와 같이 코인 가격과 거래량 리스트가 나오고 간단한 그래프가 그려지고, 코인을 선택하면 AJAX로 데이터가 변경이 되는 페이지입니다.

 

개발 완료된 웹서비스 화면
완성된 웹서비스 화면

 

1. DB 구성

H2 DB를 설치하고 DataBase를 생성합니다. 해당 내용은 이 글([H2 Database] H2 Database 설치, https://kim-oriental.tistory.com/9)을 참조 부탁드립니다.

DB 설치 후 데이터베이스를 생성해 줍니다. 해당 DB는 In-Memory의 휘발성 데이터가 아니기 때문에 항상 Server 타입으로 접속하여서 사용하시면 됩니다. DB 접속 후, 코인 정보와 가격정보를 저장할 아주 간단한 2개의 테이블을 생성해 줍니다.

 

CREATE TABLE COINS
(COINCODE VARCHAR(10) PRIMARY KEY,
COINNAME VARCHAR(25));

 

COINS 테이블은 내가 전체 코인을 관리하기가 어렵기 때문에, 내가 관리할(매수할) 코인을 골라서 그 코인 데이터를 저장하기 위한 테이블입니다. 따라서 아래와 같이 테이블 생성 후에는 내가 실제 관리할 코인 정보를 수동으로 저장해 줍니다. 예를 들어 리플과 도지 코인 2개만 Insert를 해보겠습니다. CoinCode는 API를 요청할 때 사용되므로 실제 코드를 저장합니다.

 

INSERT INTO COINS VALUES('XRP', 'Ripple');
INSERT INTO COINS VALUES('DOGE', 'DogeCoin');

 

다음으로는 가격정보가 저장될 PRICES 테이블을 생성합니다. 가격, 거래량 외 다른 데이터들도 있지만 우선 2개의 값만 저장을 하는 것으로 하겠습니다.

 

CREATE TABLE PRICES
(PNUM INT PRIMARY KEY AUTO_INCREMENT,
COINCODE VARCHAR(10) NOT NULL,
PRICE DOUBLE,
VOLUME DOUBLE,
DATE DATE);

 

2. 프로젝트 구성 및 Properties 작성

프로젝트 구성은 아래와 같이 Controller, Vo, Service, JPA Repository의 기본 구성에 지난 포스트에서 다운로드하였던, 빗썸 API 샘플 소스 파일 폴더인 External Service로 구성을 했습니다.

 

프로젝트 파일 구성 화면
프로젝트 구성

 

Property 파일은 기본 application.properties 파일을 삭제하고, 가시성이 좋은 application.yml 파일을 생성하고 아래와 같이 H2 DB 연결 관련 설정만 간략히 추가했습니다.

 

spring:
  datasource:
    url: jdbc:h2:tcp://localhost/~/oriental #H2(Server) 주소
    username: kim #아이디
    password: ㅇㅇㅇ #비밀번호
    driver-class-name: org.h2.Driver
  jpa:
    database: H2
    show-sql: true #JAP 수행 시 SQL문 로그 출력

 

3. 빗썸 API 샘플 코드 적용

빗썸의 코인의 가격정보 등 public 한 정보들을 가져오는 Public API들은 기본적인 Resttemplate이나 Webclient 등을 통해서 API를 요청하여 정보를 받아올 수 있습니다. 그러나 개인 가격정보, 매수매도 등 private API라고 불리는 API들은 지난 글(https://kim-oriental.tistory.com/4)에서 발급받은 개인 Key값과 Secret Key를 이용하여 인증된 사용자만 통신을 할 수 있습니다. 단순히 이 키값을 Header에 넣어주는 형태가 아니라, 현재 시간 데이터 등과 암호화를 거쳐서 생성된 키 값으로 통신을 하는 식인 것 같은데, 빗썸 사이트에 해당 관련 내용을 찾지를 못 했습니다. 사실 별로 알 필요성이 없는 것이 빗썸에서 제공하는 샘플 코드를 저장해서 내 프로젝트에 Import 후 이 코드를 이용해서만 통신하는 식으로 구현하면 됩니다. 내 프로젝트에 Import 하는 방법은 아래와 같습니다.

 

1. JAVA 파일 복사

먼저 다운로드한 샘플 코드 Zip 파일 압축을 풀고, src 폴더로 이동하면 4개의 파일이 있습니다. 그중 Main.java를 제외한 3개의 파일(Api_Client.java, HttpRequest.java, Util.java)을 Ctrl + C 복사해 줍니다. 다음 다시 이클립스로 와서, bitcoin/src/main/java/com/oriental/bitcoin/service/external 패키지에 Ctrl + V 붙여 넣기 하면 됩니다.

 

샘플파일 파일 리스트
빗썸 샘플파일

 

그런 후, 3개의 파일 상단에 "package com.oriental.bitcoin.coinweb.service.external;" 추가하여, 패키지 위치 정의해주면 됩니다.

 

패키지 경로 수정 화면
패키지 경로 수정

 

2. JAR 파일 등록

다시 빗썸 샘플 코드의 lib 폴더로 가면 3개의 jar 파일(commons-codec-1.10.jar, guava-18.0.jar, jackson-all-1.9.11.jar)이 존재하는데, 이것을 현재 프로젝트에 Add 시켜줍니다.

이클립스 Package Explorer에서 bitcoin 프로젝트 우클릭하여 Properties > Java Bulid Path로 이동한 후, Add External JARs를 클릭하여, lib 폴더에 있던 3개 파일을 등록합니다.

 

외부 jar파일 추가 화면
외부 Jar파일 추가

 

3. xerces 의존성 추가

위와 같이 진행을 하였는데요, 만약 Util.java 파일에서 에러가 발생하고 있다면, 아래와 같이 진행해줍니다.

샘플 코드의 JAVA 버전이 낮은 버전이라서(파일 날짜를 보면 2015년 코드네요;;;), 최신 자바 버전에는 디폴트로 설치가 안되어있는 라이브러리가 존재가 해서 발생하는 에러로 수동으로 의존성을 추가해줍니다.

pom.xml 파일 <dependencies></dependencies> 태그 중간에 아래 xerces 의존성 추가합니다. 추가 후 습관처럼 Maven > Update Project를 진행해줍니다.

 

<dependency>
<groupId>xerces</groupId>
<artifactId>xercesImpl</artifactId>
<version>2.11.0</version>
</dependency>

 

이후 다시 Util.java 파일로 와서 에러가 나고 있는 import 경로를 바꿔줍니다.

import com.sun.org.apache.xerces.internal.impl.dv.util.Base64; >> import org.apache.xerces.impl.dv.util.Base64; 

 

 

4. 서비스 개발

본격적인 서비스 개발을 진행하겠습니다. 최대한 심플하고 단순하게 기능을 구현하기 위해 구성을 해봤습니다. 사용된 기술에 대한 상세한 기본 개념은 다른 글에서 다루도록 하고, 본 포스트에서는 구현에 집중을 하고 자세한 설명은 제외하겠습니다.

 

 

 - BitcoinApplication.java : 기본 생성된 SpringBoot Application Main 파일에는 10분에 한 번씩 데이터 수집을 위해 Sheculed 어노테이션 사용을 위한, @EnableScheduling 만 추가합니다.

 

package com.oriental.bitcoin;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;

@EnableScheduling // CronTab 스케쥴 기능을 사용하기 위해 어노테이션 추가
@SpringBootApplication
public class BitcoinApplication {

	public static void main(String[] args) {
		SpringApplication.run(BitcoinApplication.class, args);
	}

}

 

 

 - CoinwebController.java : 컨트롤러 파일에는 최초 페이지 진입 시 처리를 위한 mainPage 메서드와 코인 가격정보를 AJAX 형태로 화면에 전달하기 위한 getCoinPrices 메서드(Thymeleaf AJAX 형태로 RestController에 존재하는 형태가 아님)를 추가한다.

 

package com.oriental.bitcoin.controller;

import java.util.ArrayList;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;

import com.oriental.bitcoin.model.Coins;
import com.oriental.bitcoin.model.Prices;
import com.oriental.bitcoin.service.WebPageService;

@Controller
public class CoinwebController {
	
	@Autowired
	WebPageService webPageService;
	
	@GetMapping("/") // http://localhost:8080/ 진입 시 main.html 페이지 진입을 위한 ModelandView
	public String mainPage(Model model) throws Exception {
		List<Coins> coinList = webPageService.findAllCoins();
		model.addAttribute("coinList",coinList); // 전체 코인 리스트 전달
		
		List<Prices> priceList = new ArrayList<>();
		priceList = webPageService.findPriceList(coinList.get(0).getCoincode());
		model.addAttribute("priceList",priceList); // 코인 리스트의 첫번째 코인의 가격 정보 전달
		return "main";
	}
	
	@GetMapping("/coin/prices") // AJAX 구현을 위한 Price 데이터 전달 메소드
	public String getCoinPrices(Model model, @RequestParam String coinCode) throws Exception {
		
		List<Prices> priceList = new ArrayList<>();
		priceList = webPageService.findPriceList(coinCode); // 코인코드를 파라미터로 받아, DB 조회 후 가격 정보를 전달
		model.addAttribute("priceList",priceList);
		return "main :: priceTable"; // thymeleaf AJAX 구현을 위해, 데이터가 변경 될 ":: ID" 추가
	}

}

 

 

 - Coins.java, Prices.java : 코인과 가격에 대한 객체 Model 파일, 코드 경량화를 위해 Lombok을 적용하였고 STS에 설치법은 

2021.12.07 - [기술 - JAVA/Spring Boot STS 개발 환경] - lombok(롬복) Eclipse(이클립스), STS(Spring Tool)에 설치하기

 포스트를 확인해주세요~!

 

package com.oriental.bitcoin.model;

import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;

import lombok.Getter;
import lombok.Setter;
import lombok.ToString;

@Entity
@Table(name = "COINS")
@Getter
@Setter
@ToString
public class Coins {
	
	@Id
	private String coincode;

	private String coinname;
	
}

 

 

package com.oriental.bitcoin.model;

import java.time.LocalDateTime;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

import lombok.Getter;
import lombok.Setter;
import lombok.ToString;

@Entity
@Table(name = "PRICES")
@Getter
@Setter
@ToString
public class Prices {
	
	@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
	private int pnum;
	
	private String coincode;
	
	private Double price;
	
	private Double volume;
	
	private LocalDateTime date;
	
}

 

 

 - CoinsRepository.java, PricesRepository.java : Coins 테이블과 Prices 테이블 접근을 위한 JPA CrudRepository 파일

 

package com.oriental.bitcoin.repository;

import java.util.List;

import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;

import com.oriental.bitcoin.model.Coins;

@Repository
public interface CoinsRepository extends CrudRepository<Coins, String> {
	
}

 

 

package com.oriental.bitcoin.repository;

import java.util.List;

import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;

import com.oriental.bitcoin.model.Prices;

@Repository
public interface PricesRepository extends CrudRepository<Prices, Integer>{
	
	List<Prices> findFirst10ByCoincodeOrderByDateDesc(String Coincode); // 최신 10개 가격 정보 조회
	
	Long countByCoincode(String Coincode); // 코인별 데이터 수 조회

}

 

 

 - SavePriceService.java : 10분에 한 번씩 Coins 테이블에 저장된 코인들의 가격정보를 빗썸 ticker API(https://apidocs.bithumb.com/docs/ticker)를 통해서 가져와 나의 Prices 테이블에 현재 종가와 10분간 누적 거래량을 저장해줍니다. savePriceEvery10 min 메서드에 10분 동안 거래량을 계산해서 저장하기 위한 다소 복잡한 로직이 구현이 되어 있는데요, 빗썸 API가 제공해주는 거래량 데이터가 00시 기준으로 현재까지의 거래량을 전달을 해서 이와 같이 구현이 되어있습니다. 이외 다양한 데이터들을 DB칼럼을 추가해서 저장하시고 활용을 하시면 되는데요, 저는 간단한 구현을 위해서 가격과 10분간 거래량 데이터만 저장을 하도록 하겠습니다. 그리고 이와 유사한 정보를 제공하는 candlestick API를 활용을 할 수도 있지만, 본 글의 목적이 학습의 목적이 더 크기 때문에 나만의 데이터를 직접 저장해서 관리하기 위해 이와 같이 구현을 했다는 점 참고 부탁드립니다.

 

package com.oriental.bitcoin.service;

import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.PostConstruct;
import javax.transaction.Transactional;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.oriental.bitcoin.model.Coins;
import com.oriental.bitcoin.model.Prices;
import com.oriental.bitcoin.repository.CoinsRepository;
import com.oriental.bitcoin.repository.PricesRepository;
import com.oriental.bitcoin.service.external.Api_Client;

import lombok.extern.slf4j.Slf4j;

@Service
@Transactional
@Slf4j
/* 일정 주기로 코인 가격정보를 저장하기 위한 서비스 */
public class SavePriceService {
	
	@Autowired
	CoinsRepository coinsRepository;
	@Autowired
	PricesRepository pricesRepository;
	
	// 빗썸에서 제공한 API_Client Class 정의 (API Key 와 Secret를 입력)
	static Api_Client apiClient = new Api_Client("빗썸 API KEY", "빗썸 API Secret Key");
	
	// 10분 동안 거래량 계산을 위한, 10분 전 가격 정보를 담을 Map
	static Map<String,Double> preVolumeMap = new HashMap<>();
	
	// 프로그램 실행 시 이전에 저장했던 가격 정보는 삭제
	@PostConstruct
	private void initDelAllPrices() throws Exception {
		log.info("[initDelAllPrices] 프로그램 최초 실행 시, 기존 Price 데이터 삭제 (지운 데이터: " + pricesRepository.count() + ")");
		pricesRepository.deleteAll();
	}
	
	// 10분마다 코인의 가격과 거래량 정보를 저장
	@Scheduled(cron = "30 9,19,29,39,49,59 * * * *") // 매시 09:30, 19:30, 29:30, 39:30, 49:30, 59:30에 실행
	public void savePriceEvery10min() throws Exception {
		Prices currentPrice = new Prices();
		List<Coins> coins = (List<Coins>) coinsRepository.findAll();
		log.info("[savePriceEvery10min] 10분마다 가격 정보를 저장 (현재 시간: " + LocalDateTime.now() + ", 저장할 코인 수: "+ coins.size() + ")");
		
		double curPreGap = 0.0;
		
		for(Coins c : coins) {
			currentPrice = getCoinPrice(c.getCoincode());
			if( preVolumeMap.get(c.getCoincode()) == null || pricesRepository.countByCoincode(c.getCoincode()) == 0 ) {// 최초 실행의 경우, 거래량은 0으로 현재가격을 저장
				preVolumeMap.put(c.getCoincode(), currentPrice.getVolume());
				currentPrice.setVolume(0.0);
			} else { // 직전 데이터가 있는 경우
				log.info(currentPrice.toString()+ "|" +preVolumeMap.toString());
				curPreGap = currentPrice.getVolume() - preVolumeMap.get(c.getCoincode()); // 현재 거래량에서 직전거래량을 빼면 10분 동안 거래량
				preVolumeMap.put(c.getCoincode(), currentPrice.getVolume());
				if( curPreGap >= 0 ) {
					currentPrice.setVolume(curPreGap);
				} else { // 매일 00:09:30의 경우, 빗썸 API가 00시 기준으로 리셋이 되기 때문에 그 전날 23:59:30~24:00:00의 30초동안 거래량은 버리고 00:00:00~00:09:30의 거래량만 저장 
					currentPrice.setVolume(currentPrice.getVolume());
				}
			}
			pricesRepository.save(currentPrice); // DB에 저장
		}
	}
	
	// 빗썸 API를 통해 코인의 현재 가격 정보를 가져 옴
	private Prices getCoinPrice(String coinCode) throws Exception{
		
		Prices price = new Prices();
		// 빗썸 API 호출을 위한 URL 생성
		String url = "/public/ticker/";
		url = url + coinCode + "_KRW"; 
		// 빗썸 API 호출
		HashMap<String,String> params = new HashMap<>();
		String result = apiClient.callApi(url,params);
		// 응답받은 String 데이터를 Map 객체로 저장
		ObjectMapper mapper = new ObjectMapper();
		Map<String,String> m = (Map<String, String>) mapper.readValue(result, Map.class).get("data");
		// Price 객체에 각각 응답 값을 저장
		price.setCoincode(coinCode);
		price.setPrice(Double.parseDouble(m.get("closing_price")));
		price.setVolume(Double.parseDouble(m.get("units_traded")));
		price.setDate(LocalDateTime.now());
		
		return price;
	}
}

 

 - WebPageService.java : 페이지에 정보를 주기 위한 메서드로 구성된 서비스

 

package com.oriental.bitcoin.service;

import java.time.LocalDateTime;
import java.util.*;

import javax.annotation.PostConstruct;
import javax.transaction.Transactional;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.oriental.bitcoin.model.Coins;
import com.oriental.bitcoin.model.Prices;
import com.oriental.bitcoin.repository.CoinsRepository;
import com.oriental.bitcoin.repository.PricesRepository;
import com.oriental.bitcoin.service.external.Api_Client;

import lombok.extern.slf4j.Slf4j;

@Service
@Slf4j
/* Web 페이지의 정보 노출를 위한 조회용 서비스 */
public class WebPageService {
	
	@Autowired
	CoinsRepository coinsRepository;
	@Autowired
	PricesRepository pricesRepository;
	
	// 빗썸에서 제공한 API_Client Class 정의 (API Key 와 Secret를 입력)
	static Api_Client apiClient = new Api_Client("빗썸 API KEY", "빗썸 Secret KEY");
	
	// 내가 저장한 (관리할) 모든 코인의 목록을 가져온다
	public List<Coins> findAllCoins() throws Exception{
		return (List<Coins>) coinsRepository.findAll();
	}
	// 매개 변수로 받은 코인의 최근 10개 가격 데이터 저장
	public List<Prices> findPriceList(String coinCode) throws Exception{
		return pricesRepository.findFirst10ByCoincodeOrderByDateDesc(coinCode);
	}
	

}

 

5. View Page 개발

아주 간단히 구성된 내가 저장한 데이터를 보기 위한 페이지이고 먼가 허전한 것 같아서 Apache eCharts를 활용하여 간단하게 그래프도 그려봤습니다. 그냥 Html만으로는 먼가 심심해서 (디자인 쪽은 잘 모르긴 하지만) css를 작성했으나 View 자체는 기능상 중요한 것이 아니기 때문에 참고용으로만 생각하시면 될 것 같습니다.

 

 

 - main.html

 

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Coin Web</title>
<link rel="stylesheet" href="css/main.css">
<script src="https://cdn.jsdelivr.net/npm/echarts@5.2.2/dist/echarts.min.js"></script>
<script type="text/javascript">
	window.onload = function() {
		priceAjax();
		
		document.getElementById("coinSelect").addEventListener('change', priceAjax);

		function priceAjax() { // 가격 정보를 받아오기 위한 Ajax
			var httpRequest = new XMLHttpRequest();
			var coinCD = getCoinCode();

			httpRequest.onreadystatechange = replaceContents;
			httpRequest.open('GET', 'coin/prices?coinCode=' + coinCD);
			httpRequest.send();

			function replaceContents() {
				if (httpRequest.readyState === XMLHttpRequest.DONE) {
					if (httpRequest.status === 200) {
						document.getElementById("priceTable").innerHTML = httpRequest.response;
						drawChart ();
					} else {
						alert('Request Issue!');
					}
				}
			}
			
		}

		function getCoinCode() { // 현재 Select된 코인 코드 가져옴
			var e = document.getElementById("coinSelect");
			var cd = e.options[e.selectedIndex].value;
			return cd;
		}
	}
	
	function drawChart () { // 차트를 그리기 위한 함수
		var myChart = echarts.init(document.getElementById('chart'));
		
		var priceDataList = document.getElementsByClassName('priceData');
		var priceVolumeList = document.getElementsByClassName('priceVolume');
		var priceDateList = document.getElementsByClassName('priceDate');
		
		var pList = new Array();
		var vList = new Array();
		var dList = new Array();
		for(var i=0; i < priceDataList.length; i++){
			pList[i] = priceDataList[priceDataList.length-1-i].textContent;
			vList[i] = priceVolumeList[priceDataList.length-1-i].textContent;
			dList[i] = priceDateList[priceDataList.length-1-i].textContent;
		}
		
		option = {
				  tooltip: {
				    trigger: 'axis',
				    axisPointer: {
				      type: 'cross',
				      crossStyle: {
				        color: '#999'
				      }
				    }
				  },
				  toolbox: {
				    feature: {
				      magicType: { show: true, type: ['line', 'bar'] },
				      saveAsImage: { show: true }
				    }
				  },
				  legend: {
				    data: ['거래량', '가격']
				  },
				  xAxis: [
				    {
				      type: 'category',
				      data: dList,
				      axisPointer: {
				        type: 'shadow'
				      }
				    }
				  ],
				  yAxis: [
				    {
				      type: 'value',
				      name: '거래량',
				      min: 'dataMin',
				      max: 'dataMax',
				      sacle: true
				    },
				    {
				      type: 'value',
				      name: '가격',
				      min: 'dataMin',
				      max: 'dataMax'
				    }
				  ],
				  series: [
				    {
				      name: '거래량',
				      type: 'bar',
				      data: vList
				    },
				    {
				      name: '가격',
				      type: 'line',
				      yAxisIndex: 1,
				      data: pList
				    }
				  ]
				};
		myChart.setOption(option);
	}
</script>
</head>
<body>
	<h3 id="coinSelectDiv">
		코인 선택 : <select id="coinSelect">
			<option th:each="coin : ${coinList}" th:value="${coin.coincode}"
				th:text="${coin.coinname}"></option>
		</select>
	</h3>
	<table id="priceTable" th:fragment="priceTable">
		<tr>
			<th>가격</th>
			<th>거래량</th>
			<th>시간</th>
		</tr>
		<tr th:each="price : ${priceList}">
			<td class="priceData" th:text="${price.price}" />
			<td class="priceVolume" th:text="${#numbers.formatDecimal(price.volume,0,3)}" />
			<td class="priceDate" th:text="${#temporals.format(price.date, 'MM.dd HH:mm')}" />
		</tr>
	</table>
<div id="chart">
</div>
</body>
</html>

 

 

 - main.css

 

body{
	background-color: #f4f4f4;
	color: #484848;
	font-weight: 500;
	font-family: 나눔고딕,NanumGothic;
}
select{
	color: #303030;
	font-weight: 500;
	font-family: 나눔고딕,NanumGothic;
	font-size:medium;
}
#coinSelectDiv{
	margin-top: 30px;
	margin-right: 10px;
	text-align: right;
}
table {
  border-collapse: collapse;
  border-spacing: 0;
  width: 100%;
  border: 1px solid #ddd;
  background-color: #ffffff;
  margin-top: 10px;
}
th, td {
  text-align: left;
  padding: 16px;
}

tr:nth-child(even) {
  background-color: #f2f2f2;
}
#chart{
	width: 100%;
	height: 400px;
	margin-top: 50px;
	background-color: #fff;
	padding-top: 30px;
	border-radius: 50px;
}

 

우선 현재까지 빗썸 API를 활용하여 코인의 가격정보를 받아와서 저장하고, 그것을 보여주는 아주 간단한 웹서비스를 만들어 봤습니다. 아직까지는 Public API만 사용했는데, 다음 글에서 Private API를 활용하여 나의 자산 정보를 보여주고, 간단하게 매도/매수 주문까지 할 수 있는 기능을 추가하는 내용을 다루도록 하겠습니다.

 

 

 

 

반응형

댓글