◆ HTML, Javascript, Plotly 등을 이용하여 아래 그림처럼 나만의 비트코인 차트를 만들어 보자
- 업비트 기준 코인 리스트와 실시간 시세 보여주기
- Rest API 사용 참고 브라우저 Javascript로 Rest API 요청하기 :: 코딩하는 참새 (tistory.com)
- 업비트 API 참고 분(Minute) 캔들 (upbit.com) 마켓 코드 조회 (upbit.com)
- 캔들 차트 그리기 참고 브라우저 Javascript Candle Chart 그리기 :: 코딩하는 참새 (tistory.com)
- 동시에 6개의 차트 그리기
- 선택한 시간 간격으로 차트 업데이트 하기
- 캔들 시간 (1분봉, 10분봉, 1시간봉 등) 선택 가능
- 선택한 코인들 및 시간봉 저장하기 (브라우저에서 다시 오픈하면 이전 선택사항 복원하기)
- localStorage 사용하기 참고 window.localStorage 사용으로 이전 선택 저장하기 :: 코딩하는 참새 (tistory.com)
* 차트 실행해보기 → Bitcoin Chart (sparrow-lee.github.io)
Bitcoin Chart
캔들 단위 1분 3분 5분 10분 15분 30분 1시간 4시간 업데이트 간격 없음 1초 3초 10초 30초 1분 5분 30분 1시간
sparrow-lee.github.io

onLoad 초기화 함수에서는
- 업비트에서 전체 마켓 코인 리스트를 받아와서 전역변수로 가지고 있고, (필요한 것만 재가공해서) Select태그 내부에 옵션 태그를 동적으로 추가시켜서 코인 리스트를 선택 가능하게 한다.

- 그리고, 이전에 저장했던 셋팅값들을 localStorage에서 읽어와서, 캔들 시간, 선택 코인들을 셋팅한 다음
- 차트를 그리게 한다.
console.log('> init')
await getAllCoinInfo();
console.log('getAllCoinInfo done');
setSelectTags()
console.log('set select list');
// 저장된 캔들 시간 유닛 읽어오기
gSelectedUnitIndex = getData("candleUnit");
if (gSelectedUnitIndex == undefined) {
console.log('gSelectedUnitIndex = undefined');
gSelectedUnitIndex = 7; // 디폴드 4시간봉
setData("candleUnit", 7);
}
let selectUnitElement = document.getElementById("selectUnit");
selectUnitElement.selectedIndex = gSelectedUnitIndex;
gSelectedUnitValue = selectUnitElement.options[selectUnitElement.selectedIndex].value;
console.log("selectUnitElement.options[e.selectedIndex] : " + gSelectedUnitValue);
// 유저가 선택했던 코인 리스트 읽어오기
let savedValue = getData("markets");
console.log(`getData market=${savedValue}`);
if (savedValue && savedValue.length > 3) {
let markets = savedValue.split(',');
gSelectedCoins = [];
markets.forEach(market => {
if (market != 'None') {
let info = gAllCoinsInfo.KRWDict[market];
gSelectedCoins.push({
market,
name : info.name
})
}
})
} else {
console.log('no saved data form markets')
}
let idx = 0;
gSelectedCoins.forEach(coin => {
setSelectMarket(idx, gAllCoinsInfo.KRWDict[coin.market].index + 1)
idx += 1;
})
console.log(JSON.stringify(gSelectedCoins));
console.log('> init done')
setInterval 을 이용하여 주기적으로 업데이트 되도록 함.
// 업데이트 간격 변경시
function updateIntervalOnChange(index, unit, text) {
console.log(`> updateIntervalOnChange > index=${index}, unit value=${unit}, text=${text}`);
if (gIntervalId) {
clearInterval(gIntervalId);
gInterval = 0;
}
if (unit == 'None') {
console.log('update interval = 0');
gInterval = 0;
return;
}
gInterval = gUpdateInterval[unit];
startInterval();
}
// 반복 시작
function startInterval() {
console.log("> startInterval");
if (gInterval && gInterval > 0) {
gIntervalId = setInterval(intervalHandler, gInterval);
}
}
// 반복 처리 함수. 전체 코인 시세를 가져와서 다시 그리기
async function intervalHandler() {
console.log("> intervalHandler");
await redrawAll();
}
→ setTimeout 은 한번만 수행되는 것이고, setInterval은 주기적으로 계속 반복을 하게 된다. 멈춰야 할 경우는 clearInterval을 호출하면 된다. setInterval 호출시 반환되는 intervalId를 저장해두었다가 clearInterval할 때 같이 넘겨주면 된다.
코인을 변경하였을 때 처리.
localStorage에 선택사항을 저장하고 차트를 그려준다. 6개의 차트가 있고 id가 각각 0~5번까지 있다.
None을 선택하면, div 를 hidden 처리한다.
async function selectOnChange(selId, value, text) {
console.log(`> selectOnChange${selId} : ${value}, ${text}`);
gSelectedCoins[selId] = {
market: value,
name: text,
};
let chartDivElement = document.getElementById(`chart${selId}`);
if (value == 'None') {
chartDivElement.hidden = 'hidden';
} else {
chartDivElement.hidden = undefined;
}
let markets = [];
gSelectedCoins.forEach(coin => {
if (coin.market != 'None') markets.push(coin.market);
})
console.log(markets.join(','));
setData('markets', markets.join(','));
if (value != 'None') {
let res = await getBitPrice({count: 100, market: value, unit: gSelectedUnitValue, name: text});
drawChart(res.trace, res.info, `chart${selId}`);
}
}
6개의 select와 6개의 div (차트영역)
<select name="selectMarket0" id="selectMarket0" class="form-select form-select-sm select_coin" onchange="selectOnChange(0, this.value, this.options[this.selectedIndex].text)"></select>
<select name="selectMarket1" id="selectMarket1" class="form-select form-select-sm select_coin" onchange="selectOnChange(1, this.value, this.options[this.selectedIndex].text)"></select>
<select name="selectMarket2" id="selectMarket2" class="form-select form-select-sm select_coin" onchange="selectOnChange(2, this.value, this.options[this.selectedIndex].text)"></select>
<select name="selectMarket3" id="selectMarket3" class="form-select form-select-sm select_coin" onchange="selectOnChange(3, this.value, this.options[this.selectedIndex].text)"></select>
<select name="selectMarket4" id="selectMarket4" class="form-select form-select-sm select_coin" onchange="selectOnChange(4, this.value, this.options[this.selectedIndex].text)"></select>
<select name="selectMarket5" id="selectMarket5" class="form-select form-select-sm select_coin" onchange="selectOnChange(5, this.value, this.options[this.selectedIndex].text)"></select>
<br/><br/>
<div id="chart0" style="width:100%;height:200px;float: both" hidden></div>
<div id="chart1" style="width:100%;height:200px;float: both" hidden></div>
<div id="chart2" style="width:100%;height:200px;float: both" hidden></div>
<div id="chart3" style="width:100%;height:200px;float: both" hidden></div>
<div id="chart4" style="width:100%;height:200px;float: both" hidden></div>
<div id="chart5" style="width:100%;height:200px;float: both" hidden></div>
캔들 단위와 업데이트 간격 select 태그
<table style="width:50%; min-width:300px"><tr><td>
<div style="float: left; font-size: 15px; margin:4px"> 캔들 단위 </div>
<select name="selectUnit" id="selectUnit" class="form-select form-select-sm" style="width:20%; min-width:100px; vertical-align:middle" onchange="selectUnitOnChange(this.selectedIndex, this.value, this.options[this.selectedIndex].text)">
<option id="0" value="1">1분</option>
<option id="1" value="3">3분</option>
<option id="2" value="5">5분</option>
<option id="3" value="10">10분</option>
<option id="4" value="15">15분</option>
<option id="5" value="30">30분</option>
<option id="6" value="60">1시간</option>
<option id="7" value="240">4시간</option>
</select>
</td><td>
<div style="float: left; font-size: 15px; margin:4px"> 업데이트 간격 </div>
<select name="updateInterval" id="updateInterval" class="form-select form-select-sm" style="width:20%; min-width:100px; vertical-align:middle" onchange="updateIntervalOnChange(this.selectedIndex, this.value, this.options[this.selectedIndex].text)">
<option id="0" value="None">없음</option>
<option id="1" value="1s">1초</option>
<option id="2" value="3s">3초</option>
<option id="3" value="10s">10초</option>
<option id="4" value="30s">30초</option>
<option id="5" value="1m">1분</option>
<option id="6" value="5m">5분</option>
<option id="7" value="30m">30분</option>
<option id="8" value="1h">1시간</option>
</select>
</td></tr></table>
전체 코인정보를 업비트로부터 읽어온다. 별도의 개발자 등록이나 키값이 필요하진 않다. 개인 거래이력까지 가져올려면 키를 받아오긴 해야된다.
전체 정보를 읽어와서 접근하기 쉬운형태로 재가공해서 전역변수로 가지고 있게한다.
// 전체 코인 메타 정보 가져오기
async function getAllCoinInfo() {
let url = `https://api.upbit.com/v1/market/all`;
const response = await fetch(url);
const coinInfos = await response.json();
// 코인 검색시 JSON 형태가 쉬울때가 많아서 리스트와 함께 두가지 형태로 저장한다
gAllCoinsInfo = {
"KRW" : [],
"KRWDict" : {},
};
let KRW = [], head = [];
let KRWDict = {};
coinInfos.forEach(info => {
let ids = info.market.split("-");
if (ids[0] == 'KRW') {
let name = info.korean_name;
let en_name = info.english_name;
// 비트코인과 이더리움은 정렬에서 제외시키고 맨앞에 둔다.
if (ids[1] == 'BTC' || ids[1] == 'ETH') {
head.push({
market : info.market, name, en_name,
})
} else {
KRW.push({
market : info.market, name, en_name,
})
}
}
})
KRW = KRW.sort((a, b) => a.name > b.name ? 1 : -1);
gAllCoinsInfo.KRW = head.concat(KRW);
for(let i=0; i<gAllCoinsInfo.KRW.length; i += 1) {
let coin = gAllCoinsInfo.KRW[i];
gAllCoinsInfo.KRWDict[coin.market] = {
index: i,
market: coin.market,
name: coin.name,
en_name: coin.en_name,
}
}
console.log(gAllCoinsInfo)
}
아무래도 코인 market id (예. "KRW-BTC") 로 검색을 하는 경우가 많아 JSON 형태로 데이터(gAllCoinsInfo.KRWDict)를 별도로 가지고 있게 했다. select 옵션에 넣을 때는 list형태가 편하므로 list(gAllCoinsInfo.KRW) 로도 가지고 있게했다.
특정 코인, 캔들 간격으로 시세 가져오기. 코인이 바뀔 수 있게 parameter로 넘기게 구현
// 특정 코인 캔들 정보 리스트 가져오기
async function getBitPrice({count, market, unit, name}) {
let url = `https://api.upbit.com/v1/candles/minutes/${unit}?market=${market}&count=${count}`;
const response = await fetch(url);
const prices = await response.json();
코인이 동시에 6개에, 캔들 간격, 업데이트 간격 등이 들어가게 되어서 코드가 제법 복잡해졌다.
서버 없이도 나름 쓸만한 로컬 동작가능한 차트 뷰어가 만들어 진 것 같다.

소스 코드는 아래를 참고하면 된다.
exam-codes-public/javascript/bitcoin-chart.html at main · sparrow-lee/exam-codes-public (github.com)
'SW 개발 참고 > Javascript' 카테고리의 다른 글
Javascript canvas로 슈팅 게임 만들기 (0) | 2023.11.19 |
---|---|
Javascript Canvas로 그림 그리기 (0) | 2023.11.19 |
Bootstrap을 이용하여 손쉽게 예쁜 UI 구성 (0) | 2023.11.19 |
window.localStorage 사용으로 이전 선택 저장하기 (0) | 2023.11.19 |
브라우저 Javascript Candle Chart 그리기 (0) | 2023.11.19 |