light-weight 라이브러리 사용하기

AeRi Lee·2020년 5월 10일
2

최근 작업하고 있는 페이지에서 light-weight chart라는 라이브러리를 사용했다. 매우 가볍고 간결하며 사용법도 어렵지 않다.

google에 lightweight-chart를 검색하면 TradingView페이지에서 이 라이브러리에 대해서 살펴볼 수 있다.

원하는 차트 커스텀별로 코드를 볼 수 있는데 순수자바스크립트로 이루어져 있다.
실시간으로 캔들이 그려져야 하기 때문에 리얼타임 이뮬레이션을 선택했다.

react에서

import React, { useState, useEffect, useRef } from 'react;
import { createChart } from 'light-weight-charts';

로 import 해주었고

useEffect속에는 차트를 만드는 함수 호출하는 것만 넣어줬다.

그리고 내가 원하던 것은,
1. 차트에 들어올 정보 코드 짜기 ===> 제공되는 코드를 이용하되 react에 맞춰 바꾸고 원하는 모양과 색으로 옵션을 달리 했다.
2. 차트를 원하는 곳에 넣기
이었다. ===> useRef사용했다.

const makeChart = () => {
  let chart = createChart(chartBox.current.id, {
    //첫 번째 인자로 사용된 chartBox는 ref설정 해준 div이다.
    width: 500,
    height: 300,
    layout: {
      backgroundColor: '#000000',
      textColor: 'rgba(255,255,255,0)',
    },
    crosshair: {
      mode: window.LightweightCharts.CrosshairMode.Normal,
      //원래는 이 위에 window가 없어야 한다는데 나는 window가 없으면 crosshair에 대해서 에러가 나서 window를 붙이고 진행했다.
    },
    options: {
      responsive: true,
      maintainAspectRatio: false,
    },
  });
  
  let candleSeries = chart.addCandlestickSeries({
    upColor: '',
    downColor: '',
    borderDownColor:'',
    borderUpColor: '',
    wickDownColor: '',
    wichUpColor: '',
    //원하는 색들을 넣어주면된다.
  });
  
  let data = [
    {
      time: '2020-05-09',
      open: 180.34,
      high: 180.99,
      low: 178.57,
      close: 179.85,
    },
    {
      time: '2020-05-10',
      open: 180.34,
      high: 190.99,
      low: 179.57,
      close: 185.31,
    },
    .
    .
    .
  ];
  
  candleSeries.setData(data);
  
  let lastClose = data[data.length -1].close;
  let lastIndex = data.length -1;
  
  let targetIndex = lastIndex + 105 + Math.round(Math.random() + 30);
  let targetPrice = getRandomPrice();
  
  let currentIndex = lastIndex + 1;
  let currentBusinessDay = { day: 10, month: 5, year: 2020 };
  let ticksInCurrentBar = 0;
  let currentBar = {
    open: null,
    high: null,
    low: null,
    close: null,
    time: currentBusinessDay,
  };
  
  const mergeTickToBar = (price) => {
    if (currentBar.open === null) {
        currentBar.open = price;
        currentBar.high = price;
        currentBar.low = price;
        currentBar.close = price;
      } else {
        currentBar.close = price;
        currentBar.high = Math.max(currentBar.high, price);
        currentBar.low = Math.min(currentBar.low, price);
      }
      candleSeries.update(currentBar);
  };
  
  const reset = () => {
    candleSeries.setData(data);
      lastClose = data[data.length - 1].close;
      lastIndex = data.length - 1;

      targetIndex = lastIndex + 5 + Math.round(Math.random() + 30);
      targetPrice = getRandomPrice();

      currentIndex = lastIndex + 1;
      currentBusinessDay = { day: 10, month: 5, year: 2020 };
      ticksInCurrentBar = 0;
  };
  
  const getRandomPrice = () => {
    return 10 + Math.round(Math.random() * 10000) / 100;
  };
  
  const nextBusinessDay = (time) => {
    let d = newDate();
    d.setUTCFullYear(time.year);
    d.setUTCMonth(time.month -1);
    d.setUTCDate(time.day +1);
    d.setUTCHours(0.0.0.0);
    return {
      year: d.getUTCFullYear(),
      month: d.getUTCMonth() +1,
      day: d.getUTCDate(),
    }
  };
  
  setInterval(() => {
     let deltaY = targetPrice - lastClose;
     let deltaX = targetIndex - lastIndex;
     let angle = deltaY / deltaX;
     let basePrice = lastClose + (currentIndex - lastIndex) * angle;
     let noise = 0.1 - Math.random() * 0.2 + 1.0;
     let noisedPrice = basePrice * noise;
      mergeTickToBar(noisedPrice);
      if (++ticksInCurrentBar === 5) {
        // 옆에 bar로 이동
        currentIndex++;
        currentBusinessDay = nextBusinessDay(currentBusinessDay);
        currentBar = {
          open: null,
          high: null,
          low: null,
          close: null,
          time: currentBusinessDay,
        };
        ticksInCurrentBar = 0;
        if (currentIndex === 5000) {
          reset();
          return;
        }
        if (currentIndex === targetIndex) {
          // 트렌드 바꾸기
          lastClose = noisedPrice;
          lastIndex = currentIndex;
          targetIndex = lastIndex + 5 + Math.round(Math.random() + 30);
          targetPrice = getRandomPrice();
        }
      }
    }, 5000;
  })
}

이렇게 이용했다. 그러면 캔들이 자동으로 옆에 그려진다.

실제 사용했던 코드에서도 보완해야 할 점들이 많지만 무엇보다 hook쓰는게 익숙하지 않아서 useEffect나 useRef를 사용하는 데에 있어서 버벅거렸었다. hook이 어서 익숙해지기를!

profile
👩🏻‍💻 Junior Web Frontend Developer

10개의 댓글

comment-user-thumbnail
2020년 6월 2일

안녕하세요, 혹시 제가 초보라 몇가지 여쭈고 싶은게 있어서요
하단에 가로축 날짜말고 5분단위로 22:05 이런식으로 나오게 하고 싶은데
방법 아시면 답변 주시면 감사하겠습니다.

2개의 답글
comment-user-thumbnail
2020년 6월 2일

이게 누군가 했더니...

1개의 답글
comment-user-thumbnail
2020년 11월 28일

안녕하세요 저도 차트연동하는데 어려움이있어가지고 혹시 소스코드 도움좀받을수 있을까요?
ff8lsm@naver.com 입니다 ^^

답글 달기
comment-user-thumbnail
2022년 6월 16일

좋은글 감사합니다~~ 코드중에 lastClose, lastIndex, targetIndex, targetPrice , currentIndex, ticksInCurrentBar 이 변수들이 왜필요하며 어떻게 계산을 하는건지 설명 좀 해주시면 정말 감사드리겠습니다..... 아무리 찾아봐도 위 변수에 대한 설명이 없네요 ㅜㅜ

답글 달기