본문 바로가기

사이드프로젝트/가상화폐 분석 프로그램

2장 업비트 API 분석

반응형

업비트 개발자 센터 docs.upbit.com/

 

업비트 개발자 센터

업비트 Open API 사용을 위한 개발 문서를 제공 합니다.업비트 Open API 사용하여 다양한 앱과 프로그램을 제작해보세요.

docs.upbit.com

시세 정보를 얻어올 수 있는 방식이 두가지이다. REST API와 WebSocket이용한 수신.

두 방식의 차이점은 WebSocket은 지속적인 연결된 TCP 라인을 통해 양방향 통신을 하게 된다.

고로, 과거 데이터를 조회 시에는 REST API 이용. 실시간 데이터를 받을 시에는 WebSocket으로 통신

한개씩 진행해보자. 아래와 같이 목표를 정했다

  1. REST API 를 활용하여 KST 2021-04-01부터 2021-04-13일까지 BTC 10분간격의 종가 데이터를 추출해보자
  2. REST API 를 활용하여 KST 2021-01-01부터 2021-01-02일까지 BTT 1분간격의 종가 데이터를 추출해보자
  3. REST API 를 활용하여 현재 모든 화폐 종류를 조회해보자
  4. Socket 통신을 활용하여 KRW-BTC 현재가를 5초간격으로 추출해보자
  5. Socket 통신을 활용하여 KRW-XRP 현재가를 10초간격으로 추출해보자

기본 준비

 

구글링 해본 결과 upbit 라이브러리를 만들어 놓은게 있어서 참고했다

 

note.heyo.me/%EC%97%85%EB%B9%84%ED%8A%B8api-%ED%8A%B8%EB%A0%88%EC%9D%B4%EB%94%A9-1-%EC%A4%80%EB%B9%84-%EB%B0%8F-%ED%85%8C%EC%8A%A4%ED%8A%B8/

 

//https://docs.upbit.com/v1.0.3/

const rp = require("request-promise")
const sign = require("jsonwebtoken").sign
const queryEncode = require("querystring").encode

async function request(url, qs, token, method) {
    if (!method) {
        method = 'GET'
    }
    let options = {
        method: method, 
        url: url,
        json: true,
        transform: function (body, response) {
            let remain_min = 0
            let remain_sec = 0
            if (response.headers && response.headers['remaining-req']) {
                let items = response.headers['remaining-req'].split(';')
                for (let item of items) {
                    let [key, val] = item.split('=')
                    if (key.trim()=='min') {
                        remain_min = parseInt(val.trim())
                    } else if (key.trim()=='sec') {
                        remain_sec = parseInt(val.trim())
                    }
                }
            }
            return {
                'success': true,
                'remain_min': remain_min, 
                'remain_sec': remain_sec, 
                'data': body
            }
        }
    }
    if (method=='POST') {
        options.json = qs
    } else {
        options.qs = qs
    }
    if (token) {
        options.headers = {Authorization: `Bearer ${token}`}
    }
    let result = {'success': false, 'message': null, 'name': null}
    try {
        result = await rp(options)
    } catch(e) {
        result.data = null
        if (e.error.error) {
            result.message = e.error.error.message
            result.name = e.error.error.name
        } else {
            result.message = e.message
        }
    }

    return result
}

//전체 계좌 조회
async function accounts() {
    const url = 'https://api.upbit.com/v1/accounts'

    const payload = {
        access_key: this.accessKey,
        nonce: (new Date).getTime(),
    }
    const token = sign(payload, this.secretKey)

    let result = await request(url, {}, token)
    return result
}

// 주문 리스트
async function order_list(market, state, uuids, page) {
    //market: null KRW-BTC
    //state: wait done
    const url = 'https://api.upbit.com/v1/orders'
    let qs = {state:state, page:page}
    if (market) qs['market'] = market
    if (uuids) qs['uuids'] = uuids

    const query = queryEncode(qs)
    const payload = {
        access_key: this.accessKey,
        nonce: (new Date).getTime(),
        query: query
    }
    const token = sign(payload, this.secretKey)

    let result = await request(url, qs, token)
    return result
}

// 주문(매수)
async function order_bid(market, volume, price) {
    //market: KRW-BTC
    const url = 'https://api.upbit.com/v1/orders'
    let qs = {market:market, side:'bid', volume:volume, price:price, ord_type:'limit'}

    const query = queryEncode(qs)
    const payload = {
        access_key: this.accessKey,
        nonce: (new Date).getTime(),
        query: query
    }
    const token = sign(payload, this.secretKey)

    let result = await request(url, qs, token, 'POST')
    return result
}

// 주문(매도)
async function order_ask(market, volume, price) {
    //market: KRW-BTC
    const url = 'https://api.upbit.com/v1/orders'
    let qs = {market:market, side:'ask', volume:volume, price:price, ord_type:'limit'}

    const query = queryEncode(qs)
    const payload = {
        access_key: this.accessKey,
        nonce: (new Date).getTime(),
        query: query
    }
    const token = sign(payload, this.secretKey)

    let result = await request(url, qs, token, 'POST')
    return result
}

// 주문 상세
async function order_detail(uuid) {
    const url = 'https://api.upbit.com/v1/order'
    let qs = {uuid:uuid}

    const query = queryEncode(qs)
    const payload = {
        access_key: this.accessKey,
        nonce: (new Date).getTime(),
        query: query
    }
    const token = sign(payload, this.secretKey)

    let result = await request(url, qs, token)
    return result
}

// 주문 취소
async function order_delete(uuid) {
    const url = 'https://api.upbit.com/v1/order'
    let qs = {uuid:uuid}

    const query = queryEncode(qs)
    const payload = {
        access_key: this.accessKey,
        nonce: (new Date).getTime(),
        query: query
    }
    const token = sign(payload, this.secretKey)

    let result = await request(url, qs, token, 'DELETE')
    return result
}

// 주문 가능 정보
async function order_chance(market) {
    const url = 'https://api.upbit.com/v1/orders/chance'
    let qs = {market:market}

    const query = queryEncode(qs)
    const payload = {
        access_key: this.accessKey,
        nonce: (new Date).getTime(),
        query: query
    }
    const token = sign(payload, this.secretKey)

    let result = await request(url, qs, token)
    return result
}

// 시세종목정보
async function market_all() {
    const url = 'https://api.upbit.com/v1/market/all'
    let result = await request(url)
    return result
}

// 분 캔들
async function market_minute(market, unit, to, count) {
    //unit:  1, 3, 5, 15, 10, 30, 60, 240
    //to: yyyy-MM-dd'T'HH:mm:ssXXX
    const url = 'https://api.upbit.com/v1/candles/minutes/'+unit
    let qs = {market:market}
    if (to) qs.to = to
    if (count) qs.count = count

    let result = await request(url, qs)
    return result
}

// 일 캔들
async function market_day(market, to, count) {
    //to: yyyy-MM-dd'T'HH:mm:ssXXX
    const url = 'https://api.upbit.com/v1/candles/days'
    let qs = {market:market}
    if (to) qs.to = to
    if (count) qs.count = count

    let result = await request(url, qs)
    return result
}

// 주 캔들
async function market_week(market, to, count) {
    //to: yyyy-MM-dd'T'HH:mm:ssXXX
    const url = 'https://api.upbit.com/v1/candles/weeks'
    let qs = {market:market}
    if (to) qs.to = to
    if (count) qs.count = count

    let result = await request(url, qs)
    return result
}

// 월 캔들
async function market_month(market, to, count) {
    //to: yyyy-MM-dd'T'HH:mm:ssXXX
    const url = 'https://api.upbit.com/v1/candles/months'
    let qs = {market:market}
    if (to) qs.to = to
    if (count) qs.count = count

    let result = await request(url, qs)
    return result
}

// 채결 정보
async function market_trade_tick(market, to, count) {
    //to: yyyy-MM-dd'T'HH:mm:ssXXX
    const url = 'https://api.upbit.com/v1/trades/ticks'
    let qs = {market:market}
    if (to) qs.to = to
    if (count) qs.count = count

    let result = await request(url, qs)
    return result
}


// 시세 Ticker
async function market_ticker(markets) {
    // markets: KRW-BTC,KRW-ETH
    const url = 'https://api.upbit.com/v1/ticker'
    let qs = {markets:markets}

    let result = await request(url, qs)
    return result
}


// 호가 정보
async function trade_orderbook(markets) {
    // markets: KRW-BTC,KRW-ETH
    const url = 'https://api.upbit.com/v1/orderbook'
    let qs = {markets:markets}

    let result = await request(url, qs)
    return result
}

// class Upbit
function Upbit(s, a) {
    this.secretKey = s
    this.accessKey = a
}
Upbit.prototype.accounts = accounts
Upbit.prototype.order_list = order_list
Upbit.prototype.order_bid = order_bid
Upbit.prototype.order_ask = order_ask
Upbit.prototype.order_detail = order_detail
Upbit.prototype.order_delete = order_delete
Upbit.prototype.order_chance = order_chance
Upbit.prototype.market_all = market_all
Upbit.prototype.market_minute = market_minute
Upbit.prototype.market_day = market_day
Upbit.prototype.market_week = market_week
Upbit.prototype.market_month = market_month
Upbit.prototype.market_trade_tick = market_trade_tick
Upbit.prototype.market_ticker = market_ticker
Upbit.prototype.trade_orderbook = trade_orderbook

module.exports = Upbit

 

1. REST API 를 활용하여 KST 2021-04-01부터 2021-04-13일까지 BTC 10분간격의 종가 데이터를 추출해보자

const Upbit = require('./upbit_lib')
const fs = require('fs');


async function start() {
    const upbit = new Upbit('secret-key', 'access-key');

    let date = new Date('2020-04-14T00:00:00Z'); // 원하는 한국 시간 입력 (utc+9 시간))
    convertKSTtoUTC(date);
    let cDate = date;
    let desDate = new Date('2020-04-01T00:00:00Z');
    convertKSTtoUTC(desDate);
    let json;
    let timerID = null;

    async function lookup()
    {
    
        while (cDate >= desDate) {
            json = await upbit.market_minute('KRW-BTC', 10, cDate, 240); 
            /*
                10분단위로 240개를 조회(upbit에서 제공하는 최대 조회횟수) 하는데 2020-04-14 00:00:00 으로 조회하면
                2020-04-13 23:50:00 데이터 
                2020-04-13 23:40:00 데이터
                2020-04-13 23:30:00 데이터 
                ...
                2020-03-31 xx:xx:xx 데이터 (240개에 걸려서 2020-04-01 00:00:00 으로 딱 맞춰서 나오진 않음)

            */
            if(json.data !== null) // 데이터를 수신 받지 못한 경우 대비
            {
                let arr = json.data;
                // 240개에 걸려서 2020-04-01 00:00:00 으로 딱 맞춰서 나오진 않으니 해당 처리
                json.data.some(function(element,index) {
                    if(new Date(element['candle_date_time_kst']) < desDate)
                    {
                        arr = json.data.slice(0,index);
                        return true;    
                        
                    }
                });

                // output.txt 파일로 해당 결과 출력
                // writeFile을 안쓰고 appendFile(이어서 계속 쓰기) 를 쓴 이유는 while 문 돌때마다 다시 파일 쓰기때문에 이전 내역이 지워짐
                fs.appendFile('./output.txt',JSON.stringify(arr),function(err){
                    if(err){
                        console.log('err'+err);
                    }
                })

                // 240 개 조회 뒤 다음위치로 이동 
                // 2020-04-14 00:00:00 넣으면 2020-04-13 23:50:00(10분 결과) 으로 나오니깐 마지막 값을 넣어줌
                cDate = new Date(json.data[json.data.length - 1]['candle_date_time_kst']);
            }
        
        }
        clearInterval(timerID);
    }
    // 2초정도로 반복해야 응답요청이 원활
    timerID = setInterval(lookup,2000); 

}

// 한국시간 입력 시 UTC로 바꾸줌
function convertKSTtoUTC(date) {
    date.setHours(date.getHours() - 9);
}

start()

 

2. REST API 를 활용하여 KST 2021-01-01부터 2021-01-02일까지 BTT 1분간격의 종가 데이터를 추출해보자

// 작성중 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

const Upbit = require('./upbit_lib')
const fs = require('fs');


async function start() {
    const upbit = new Upbit('secret-key', 'access-key');

    let date = new Date('2020-01-03T00:00:00Z'); // 원하는 한국 시간 입력 (utc+9 시간))
    convertKSTtoUTC(date);
    let cDate = date;
    let desDate = new Date('2020-01-01T00:00:00Z');
    convertKSTtoUTC(desDate);
    let json;
    let timerID = null;

    async function lookup()
    {
    
        while (cDate >= desDate) {
            json = await upbit.market_minute('KRW-BTT', 1, cDate, 240); 
            /*
                1분단위로 240개를 조회(upbit에서 제공하는 최대 조회횟수) 하는데 2020-01-03 00:00:00 으로 조회하면
                2020-01-02 23:59:00 데이터 
                2020-01-02 23:58:00 데이터
                2020-01-02 23:57:00 데이터 
                ...
                2019-12-31 xx:xx:xx 데이터 (240개에 걸려서 2020-01-01 00:00:00 으로 딱 맞춰서 나오진 않음)

            */
		//    console.log('json.data',json.data);
            if(json.data !== null) // 데이터를 수신 받지 못한 경우 대비
            {
                let arr = json.data;
                // 240개에 걸려서 2020-01-01 00:00:00 으로 딱 맞춰서 나오진 않으니 해당 처리
                json.data.some(function(element,index) {
                    if(new Date(element['candle_date_time_kst']) < desDate)
                    {
                        arr = json.data.slice(0,index);
                        return true;    
                        
                    }
                });

                // output2.txt 파일로 해당 결과 출력
                // writeFile을 안쓰고 appendFile(이어서 계속 쓰기) 를 쓴 이유는 while 문 돌때마다 다시 파일 쓰기때문에 이전 내역이 지워짐
                fs.appendFile('./output2.txt',JSON.stringify(arr),function(err){
                    if(err){
                        console.log('err'+err);
                    }
                })

                // 240 개 조회 뒤 다음위치로 이동 
                // 2020-01-03 00:00:00 넣으면 2020-01-02 23:59:00(1분 결과) 으로 나오니깐 마지막 값을 넣어줌
                cDate = new Date(json.data[json.data.length - 1]['candle_date_time_kst']);
            }
        
        }
        clearInterval(timerID);
    }
    // 2초정도로 반복해야 응답요청이 원활
    timerID = setInterval(lookup,2000); 

}

// 한국시간 입력 시 UTC로 바꾸줌
function convertKSTtoUTC(date) {
    date.setHours(date.getHours() - 9);
}

start()

 

3. REST API 를 활용하여 현재 모든 화폐 종류를 조회해보자

const Upbit = require('./upbit_lib')
const fs = require('fs');


async function start() {
	const upbit = new Upbit('secret-key', 'access-key');
	let json = await upbit.market_all();
	console.log('json.data',json.data);

	fs.appendFile('./marketAll.txt',JSON.stringify(json.data),function(err){
		if(err){
			console.log('err'+err);
		}
	})
}

start()

 

4. Socket 통신을 활용하여 BTC 현재가를 5초간격으로 추출해보자

const WebSocket = require('ws')

let recvData = "";

function tradeServerConnect(codes) {
    let ws = new WebSocket('wss://api.upbit.com/websocket/v1');
    ws.on('open', ()=>{
        console.log('trade websocket is connected')
        const str = `[{"ticket":"find"},{"type":"trade","codes":["${codes}"]}]`;
        ws.send(str);
    })  
    ws.on('close', ()=>{
        console.log('trade websocket is closed');
        setTimeout(function() {
            console.log('trade 재접속');
            tradeServerConnect(codes);
        }, 1000);
    })  
    ws.on('message', (data)=>{
        try {
            let str = data.toString('utf-8')
            recvData = JSON.parse(str)
        } catch (e) {
            console.log(e)
        }
    })
}

async function start() {
	tradeServerConnect('KRW-BTC')
    function print()
    {
        console.log('recvData',recvData['trade_price']);
    }
    setInterval(print,5000);

}

start()

 

5. Socket 통신을 활용하여 KRW-XRP 현재가를 10초간격으로 추출해보자

const WebSocket = require('ws')

let recvData = "";

function tradeServerConnect(codes) {
    console.log('codes',codes);
    let ws = new WebSocket('wss://api.upbit.com/websocket/v1');
    ws.on('open', ()=>{
        console.log('trade websocket is connected')
        const str = `[{"ticket":"find"},{"type":"trade","codes":${codes}}]`;
        ws.send(str);
    })  
    ws.on('close', ()=>{
        console.log('trade websocket is closed');
        setTimeout(function() {
            console.log('trade 재접속');
            tradeServerConnect(codes);
        }, 1000);
    })  
    ws.on('message', (data)=>{
		// console.log('data',data);
        try {
            let str = data.toString('utf-8')
            recvData = JSON.parse(str)
            // console.log('recvData',recvData);
        } catch (e) {
            console.log(e)
        }
    })
}

async function start() {
	tradeServerConnect("[\"KRW-BTC\"]")
    function print()
    {
        console.log('recvData',recvData['trade_price']);
    }
    setInterval(print,10000);

}

start()
반응형

'사이드프로젝트 > 가상화폐 분석 프로그램' 카테고리의 다른 글

1장 프로토타입  (0) 2021.04.08