cryptocurrency.api
Version:
Cryptocurrency API
352 lines (351 loc) • 15.3 kB
JavaScript
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.UPbit = exports.RequestError = void 0;
const axios_1 = require("axios");
const uuid_1 = require("uuid");
const jsonwebtoken_1 = require("jsonwebtoken");
const crypto = require("crypto");
const querystring_1 = require("querystring");
const utils_1 = require("./utils");
const fourdollar_1 = require("fourdollar");
function reference(obj, ...datums) {
return datums.reduce((obj, d) => {
if (!obj) {
return obj;
}
return obj[d];
}, obj);
}
class RequestError extends Error {
constructor(axiosError) {
const message = reference(axiosError, 'response', 'data', 'error', 'message');
if (message) {
super(message);
}
else {
super(axiosError.message);
}
const code = reference(axiosError, 'response', 'data', 'error', 'name');
if (code) {
this.code = code;
}
this.url = reference(axiosError, 'config', 'url');
this.method = reference(axiosError, 'config', 'method');
this.params = reference(axiosError, 'config', 'params');
this.status = reference(axiosError, 'response', 'status');
this.statusText = reference(axiosError, 'response', 'statusText');
}
}
exports.RequestError = RequestError;
/**
* UPbit
**/
class UPbit {
constructor(options) {
this._url = 'https://api.upbit.com/v1';
this._opts = Object.assign({}, options);
}
/**
* 마켓 코드 조회
* 업비트에서 거래 가능한 마켓 목록
* https://docs.upbit.com/reference#%EB%A7%88%EC%BC%93-%EC%BD%94%EB%93%9C-%EC%A1%B0%ED%9A%8C
* isDetails: 유의종목 필드과 같은 상세 정보 노출 여부(선택 파라미터)
**/
getMarket(isDetails = false) {
return this._quotation('/market/all', { isDetails });
}
/**
* 분(Minute) 캔들
* https://docs.upbit.com/reference#%EB%B6%84minute-%EC%BA%94%EB%93%A4-1
* min: 분 단위. 가능한 값 : 1, 3, 5, 15, 10, 30, 60, 240 (필수)
* CandleParam.market: 마켓 코드 (ex. KRW-BTC) (필수)
* CandleParam.to: 마지막 캔들 시각 (exclusive). 포맷 : yyyy-MM-dd'T'HH:mm:ssXXX or yyyy-MM-dd HH:mm:ss. 비워서 요청시 가장 최근 캔들
* CandleParam.cout: 캔들 개수(최대 200개까지 요청 가능)
**/
getCandlesMinutes(min, params) {
return this._quotation(`/candles/minutes/${min}`, params);
}
/**
* 일(Day) 캔들
* https://docs.upbit.com/reference#%EC%9D%BCday-%EC%BA%94%EB%93%A4-1
* CandleParamEx.market: 마켓 코드 (ex. KRW-BTC, BTC-BCC) (필수)
* CandleParamEx.to: 마지막 캔들 시각 (exclusive). 포맷 : yyyy-MM-dd'T'HH:mm:ssXXX or yyyy-MM-dd HH:mm:ss. 비워서 요청시 가장 최근 캔들
* CandleParamEx.count: 캔들 개수
* CandleParamEx.convertingPriceUnit: 종가 환산 화폐 단위 (생략 가능, KRW로 명시할 시 원화 환산 가격을 반환.)
**/
getCandlesDays(params) {
return this._quotation('/candles/days', params);
}
/**
* 주(Week) 캔들
* https://docs.upbit.com/reference#%EC%A3%BCweek-%EC%BA%94%EB%93%A4-1
* CandleParam.market: string 마켓 코드 (ex. KRW-BTC, BTC-BCC) (필수)
* CandleParam.to: string 마지막 캔들 시각 (exclusive). 포맷 : yyyy-MM-dd'T'HH:mm:ssXXX or yyyy-MM-dd HH:mm:ss. 비워서 요청시 가장 최근 캔들
* CandleParam.count: int32 캔들 개수
**/
getCandlesWeeks(params) {
return this._quotation('/candles/weeks', params);
}
/**
* 월(Month) 캔들
* https://docs.upbit.com/reference#%EC%9B%94month-%EC%BA%94%EB%93%A4-1
* CandleParam.market: string 마켓 코드 (ex. KRW-BTC, BTC-BCC) (필수)
* CandleParam.to: string 마지막 캔들 시각 (exclusive). 포맷 : yyyy-MM-dd'T'HH:mm:ssXXX or yyyy-MM-dd HH:mm:ss. 비워서 요청시 가장 최근 캔들
* CandleParam.count: int32 캔들 개수
**/
getCandlesMonths(params) {
return this._quotation('/candles/months', params);
}
/**
* 최근 체결 내역
* https://docs.upbit.com/reference#%EC%B5%9C%EA%B7%BC-%EC%B2%B4%EA%B2%B0-%EB%82%B4%EC%97%AD
* TradeTickParam.market*: string 마켓 코드 (ex. KRW-BTC, BTC-BCC)
* TradeTickParam.to: string 마지막 체결 시각. 형식 : [HHmmss 또는 HH:mm:ss]. 비워서 요청시 가장 최근 데이터
* TradeTickParam.count: int32 체결 개수
* TradeTickParam.cursor: string 페이지네이션 커서 (sequentialId)
* TradeTickParam.daysAgo: int32 최근 체결 날짜 기준 7일 이내의 이전 데이터 조회 가능. 비워서 요청 시 가장 최근 체결 날짜 반환. (범위: 1 ~ 7))
**/
getTradesTicks(params) {
return this._quotation('/trades/ticks', params);
}
/**
* 현재가 정보
* 요청 당시 종목의 스냅샷을 반환한다.
* https://docs.upbit.com/reference#ticker%ED%98%84%EC%9E%AC%EA%B0%80-%EB%82%B4%EC%97%AD
* markets*: string 반점으로 구분되는 마켓 코드 (ex. KRW-BTC, BTC-BCC)
**/
getTicker(params) {
const pp = { markets: params.markets.join(', ') };
return this._quotation('/ticker', pp);
}
/**
* 호가 정보 조회
* https://docs.upbit.com/reference#%ED%98%B8%EA%B0%80-%EC%A0%95%EB%B3%B4-%EC%A1%B0%ED%9A%8C
* markets*: array of strings 마켓 코드 목록 (ex. KRW-BTC,KRW-ADA)
**/
getOrderbook(params) {
const pp = { markets: params.markets.join(', ') };
return this._quotation('/orderbook', pp);
}
/**
* 전체 계좌 조회
* 내가 보유한 자산 리스트를 보여줍니다.
* https://docs.upbit.com/reference#%EC%9E%90%EC%82%B0-%EC%A1%B0%ED%9A%8C
**/
getAccounts() {
return __awaiter(this, void 0, void 0, function* () {
const res = yield this._exchange('/accounts', 'GET');
res.data = (0, utils_1.toNumbers)(res.data);
return res;
});
}
/**
* 주문 가능 정보
* https://docs.upbit.com/reference#%EC%A3%BC%EB%AC%B8-%EA%B0%80%EB%8A%A5-%EC%A0%95%EB%B3%B4
* market *: 마켓ID String
**/
getOrdersChance(params) {
return __awaiter(this, void 0, void 0, function* () {
const res = yield this._exchange('/orders/chance', 'GET', { params });
res.data = (0, utils_1.toNumbers)(res.data);
return res;
});
}
/**
* 개별 주문 조회
* 주문 UUID 를 통해 개별 주문건을 조회한다.
* https://docs.upbit.com/reference#%EA%B0%9C%EB%B3%84-%EC%A3%BC%EB%AC%B8-%EC%A1%B0%ED%9A%8C
* uuid: 주문 UUID String
* identifier: 조회용 사용자 지정 값 String
**/
getOrderDetail(params) {
return __awaiter(this, void 0, void 0, function* () {
const res = yield this._exchange('/order', 'GET', { params });
res.data = (0, utils_1.toNumbers)(res.data);
return res;
});
}
/**
* 주문 리스트 조회
* 주문 리스트를 조회한다.
* https://docs.upbit.com/reference#%EC%A3%BC%EB%AC%B8-%EB%A6%AC%EC%8A%A4%ED%8A%B8-%EC%A1%B0%ED%9A%8C
* market: 마켓 아이디 String
* uuids: 주문 UUID의 목록 Array
* identifiers: 주문 identifier의 목록 Array
* state: 주문 상태 String
* - wait : 체결 대기 (default)
* - watch : 예약주문 대기
* - done : 전체 체결 완료
* - cancel : 주문 취소
* states: 주문 상태의 목록 Array
* * 미체결 주문(wait, watch)과 완료 주문(done, cancel)은 혼합하여 조회하실 수 없습니다.
* page: 페이지 수, default: 1 Number
* limit: 요청 개수, default: 100 Number
* order_by: 정렬 방식
* - asc : 오름차순
* - desc : 내림차순 (default) String
**/
getOrderList(params) {
return __awaiter(this, void 0, void 0, function* () {
const res = yield this._exchange('/orders', 'GET', { params });
res.data = (0, utils_1.toNumbers)(res.data);
return res;
});
}
/**
* 주문 취소 접수
* 주문 UUID를 통해 해당 주문에 대한 취소 접수를 한다.
* https://docs.upbit.com/reference#주문-취소
* uuid: 취소할 주문의 UUID String
* identifier: 조회용 사용자 지정값 String
**/
cancel(params) {
return __awaiter(this, void 0, void 0, function* () {
const res = yield this._exchange('/order', 'DELETE', { params });
res.data = (0, utils_1.toNumbers)(res.data);
return res;
});
}
/**
* 주문하기
* 주문 요청을 한다.
* https://docs.upbit.com/reference#%EC%A3%BC%EB%AC%B8%ED%95%98%EA%B8%B0
* market * 마켓 ID (필수) String
* side * 주문 종류 (필수)
* - bid : 매수
* - ask : 매도 String
* volume * 주문량 (지정가, 시장가 매도 시 필수) NumberString
* price * 주문 가격. (지정가, 시장가 매수 시 필수)
* ex) KRW-BTC 마켓에서 1BTC당 1,000 KRW로 거래할 경우, 값은 1000 이 된다.
* ex) KRW-BTC 마켓에서 1BTC당 매도 1호가가 500 KRW 인 경우, 시장가 매수 시 값을 1000으로 세팅하면 2BTC가 매수된다.
* (수수료가 존재하거나 매도 1호가의 수량에 따라 상이할 수 있음) NumberString
* ord_type * 주문 타입 (필수)
* - limit : 지정가 주문
* - price : 시장가 주문(매수)
* - market : 시장가 주문(매도) String
* identifier 조회용 사용자 지정값 (선택) String (Uniq 값 사용)
* --
* 원화 마켓 가격 단위를 확인하세요.
* 원화 마켓에서 주문을 요청 할 경우, 원화 마켓 주문 가격 단위 를 확인하여 값을 입력해주세요.
* --
* identifier 파라미터 사용
* identifier는 서비스에서 발급하는 uuid가 아닌 이용자가 직접 발급하는 키값으로, 주문을 조회하기 위해 할당하는 값입니다. 해당 값은 사용자의 전체 주문 내 유일한 값을 전달해야하며, 비록 주문 요청시 오류가 발생하더라도 같은 값으로 다시 요청을 보낼 수 없습니다.
* 주문의 성공 / 실패 여부와 관계없이 중복해서 들어온 identifier 값에서는 중복 오류가 발생하니, 매 요청시 새로운 값을 생성해주세요.
* --
* 시장가 주문
* 시장가 주문은 ord_type 필드를 price or market 으로 설정해야됩니다.
* 매수 주문의 경우 ord_type을 price로 설정하고 volume을 null 혹은 제외해야됩니다.
* 매도 주문의 경우 ord_type을 market로 설정하고 price을 null 혹은 제외해야됩니다.
**/
order(params) {
return __awaiter(this, void 0, void 0, function* () {
const res = yield this._exchange('/orders', 'POST', { params });
res.data = (0, utils_1.toNumbers)(res.data);
return res;
});
}
_quotation(endPoint, params) {
return __awaiter(this, void 0, void 0, function* () {
try {
const res = yield (0, axios_1.default)({ method: 'GET', url: `${this._url}${endPoint}`, params });
return {
status: res.status,
remainingReq: this._extractRemainingReq(res.headers),
data: res.data,
};
}
catch (e) {
if (e.isAxiosError) {
const err = new RequestError(e);
if (err.status === 429) {
yield (0, fourdollar_1.stop)(100);
return this._quotation(endPoint, params);
}
else {
throw err;
}
}
else {
throw e;
}
}
});
}
_exchange(endPoint, method, { params, data } = {}) {
return __awaiter(this, void 0, void 0, function* () {
const payload = {
access_key: this._opts.accessKey,
nonce: (0, uuid_1.v4)(),
};
let pp;
if (params) {
pp = {};
for (let key in params) {
if (Array.isArray(params[key])) {
pp[`${key}[]`] = params[key];
}
else {
pp[key] = params[key];
}
}
const query = (0, querystring_1.stringify)(pp);
const hash = crypto.createHash('sha512');
const queryHash = hash.update(query, 'utf8').digest('hex');
Object.assign(payload, {
query_hash: queryHash,
query_hash_alg: 'SHA512',
});
}
const token = (0, jsonwebtoken_1.sign)(payload, this._opts.secretKey);
try {
const res = yield (0, axios_1.default)({
method,
url: `${this._url}${endPoint}`,
headers: {
Authorization: `Bearer ${token}`,
},
params: pp,
//data: params,
});
return {
status: res.status,
remainingReq: this._extractRemainingReq(res.headers),
data: res.data,
};
}
catch (e) {
if (e.isAxiosError) {
const err = new RequestError(e);
if (err.status === 429) {
yield (0, fourdollar_1.stop)(100);
return this._exchange(endPoint, method, { params, data });
}
else {
throw err;
}
}
else {
throw e;
}
}
});
}
_extractRemainingReq(headers) {
return headers['remaining-req'].split(';').map(a => a.trim())
.reduce((o, a) => {
const c = a.split('=');
o[c[0]] = isNaN(parseInt(c[1])) ? c[1] : parseInt(c[1]);
return o;
}, {});
}
}
exports.UPbit = UPbit;