Act99 기술블로그

[React] 직접 주가 캔들 차트 만들기5 (이동평균선 추가) (SVG 연습용) 본문

개발팁저장소/react

[React] 직접 주가 캔들 차트 만들기5 (이동평균선 추가) (SVG 연습용)

Act99 2021. 12. 1. 16:41

저번 글에서 봤듯이 차트를 확대할 때, 과거 데이터를 가져오는 문제가 있었다.

 

https://bugerstory.tistory.com/35

 

[React] 직접 주가 캔들 차트 & 거래량 바 차트 만들기4 - onWheel 을 통해 데이터값을 추가시키거나

오늘은 onWheel 을 통해 데이터 값을 추가 또는 감소시키는 작업을 했다. 그 전에 만들었던 코드를 일단 정리했다. stock.tsx 파일에서 불러오는 데이터를 handmade-chart.tsx 로 옮겼으며, 안쓰는 코드들

bugerstory.tistory.com

 

이 문제를 수정하기 위해 slice를 사용했다.

 

  const [dataLength, setDataLength] = useState(24);

  const stockData = data?.gsStock.map((item) => item);
  const stockDummyArray: any[] = [];
  stockData?.forEach((item) => stockDummyArray.push(item));

  const stockArray: any[] = [];
  console.log(dataLength);
  stockData
    ?.slice(dataLength, stockDummyArray.length)
    .forEach((item) => stockArray.push(item));
  console.log(stockArray[0]);

  const dataWheelHandler = () => {
    window.onwheel = function (e) {
      e.deltaY > 0
        ? setDataLength(dataLength < 18 ? dataLength + 0 : dataLength - 8)
        : setDataLength(
            dataLength > stockDummyArray?.length - 18
              ? dataLength + 0
              : dataLength + 8
          );
    };
  };

 

stockData?.slice(dataLength, stockDummyArray.length) 를 통해

dataLength 부터 전체 데이터까지의 데이터를 가져왔다.

 

 

다음은 캔들차트 수정이다.

고가, 저가 축의 x좌표를 변경시켜주었다.

         <line
                x1={x + (barPlothWidth - sidePadding) / 2}
              
                x2={x + (barPlothWidth - sidePadding) / 2}
                y1={yAxisLength - scaleY(low)}
                y2={yAxisLength - scaleY(high)}
                stroke={open > close ? "red" : "green"}
              />
              <rect
                {...{ fill }}
                x={x}
                width={barPlothWidth - sidePadding}
                y={yAxisLength - scaleY(max)}
                // 시가 종가 최대 최소값의 차
                height={scaleY(max) - scaleY(min)}
              ></rect>

시가 종가 차트의 너비의 평균값을 x좌표로 잡아주었다.

 

그 결과

 

 

잘 작동했다.

 

다음으로는 거래량 차트이다.

거래량 차트는 매도가 많을 때, 빨간색, 매수가 많을 때 초록색으로 구현해야 한다.

하지만 내가 가져온 데이터는 매도, 매수량이 없다. (아쉽게도 ㅠㅠ)

 

따라서 데이터의 한계로 주가가 오를 때 매수가 많으며 주가가 떨어질 때 매도수량이 많은 것으로 측정했다.

 

**보통 주가는 고가와 종가 차이가 클때 매도수량이 높지만(경험상) 이 역시 정확하지 않기 때문에

주가가 오를 때 매수수량이 많고 주가가 떨어질 때 매도수량이 많은 것으로 측정했다.**

 

 const fill = close > open ? "#4AFA9A" : "#E33F64";
          return (
            <g key={index}>
              <rect
                {...{ fill }}
                x={x}
                y={y}
                width={barPlotWidth - sidePadding}
                height={height}
              ></rect>
            </g>

 

아쉽지만 그래도 거래량 차트까지 구현했다.

 

여기서 한 가지 문제점을 더 발견했는데,

날짜 데이터가 정확하게 따라오지 않는다는 것이었다.

이 문제는 모든 차트들을 구현한 후, 손을 볼 예정이다.

 

다음은 이동평균선을 만들어 줄 것이다.

먼저 이동평균선 데이터를 가져와준다.

 

  const stockClo5 = stockArray.map((item) => item.clo5);
  const clo5Array: number[] = [];
  stockClo5?.forEach((clo5) => clo5Array.push(clo5));

  const stockClo20 = stockArray.map((item) => item.clo20);
  const clo20Array: number[] = [];
  stockClo20?.forEach((clo20) => clo20Array.push(clo20));

  const stockClo60 = stockArray.map((item) => item.clo60);
  const clo60Array: number[] = [];
  stockClo60?.forEach((clo60) => clo60Array.push(clo60));

 

다음 CandleChart 의 dataArray 에 추가시켜준다.

 

  const clo5Array: [number, number][] = [];
  const clo20Array: [number, number][] = [];
  const clo60Array: [number, number][] = [];
  const dataArray: [
    string,
    number,
    number,
    number,
    number,
    number[],
    number[],
    number[]
  ][] = [];
  for (let i = 0; i < date.length; i++) {
    clo5Array.push([clo5[i], clo5[i + 1] == undefined ? clo5[i] : clo5[i + 1]]);
    clo20Array.push([
      clo20[i],
      clo20[i + 1] == undefined ? clo20[i] : clo20[i + 1],
    ]);
    clo60Array.push([
      clo60[i],
      clo60[i + 1] == undefined ? clo60[i] : clo60[i + 1],
    ]);
    dataArray.push([
      date[i],
      open[i],
      close[i],
      high[i],
      low[i],
      clo5Array[i],
      clo20Array[i],
      clo60Array[i],
    ]);
  }

undefined 이 필요한 이유는 마지막 i+1 번째는 무조건 undefined이 나오기 때문이다. (데이터가 없기 때문)

 

그리고 svg에 그려준다.

여기서 중요한건, 이동평균선은 전날과 현재 데이터가 일치할 수 없기 때문에 이를 이용해서 전에 undefined일 때 전날과 현재데이터를 같게 하라는 코드를 빼주어야 한다.

 

코드는 이렇다.

 

 

       {clo5[0] > dataYMin && clo5[0] != clo5[1] ? (
                  <line
                    stroke="green"
                    x1={x + (barPlothWidth - sidePadding) / 2}
                    x2={xX + (barPlothWidth - sidePadding) / 2}
                    y1={yAxisLength - scaleY(clo5[0])}
                    y2={yAxisLength - scaleY(clo5[1])}
                  />
                ) : null}
                {clo20[0] > dataYMin && clo20[0] != clo20[1] ? (
                  <line
                    stroke="red"
                    x1={x + (barPlothWidth - sidePadding) / 2}
                    x2={xX + (barPlothWidth - sidePadding) / 2}
                    y1={yAxisLength - scaleY(clo20[0])}
                    y2={yAxisLength - scaleY(clo20[1])}
                  />
                ) : null}
                {clo60[0] > dataYMin && clo60[0] != clo60[1] ? (
                  <line
                    stroke="gold"
                    x1={x + (barPlothWidth - sidePadding) / 2}
                    x2={xX + (barPlothWidth - sidePadding) / 2}
                    y1={yAxisLength - scaleY(clo60[0])}
                    y2={yAxisLength - scaleY(clo60[1])}
                  />
                ) : null}

 

결과는..

 

 

이동평균선이 잘 만들어진 것을 확인할 수 있다.

 

앞으로 할 일은 볼린저 밴더 형성, 틱 정보 얻기이다.

 

https://github.com/act99/stock-frontend

 

GitHub - act99/stock-frontend: Stock Chart & Livechat on website. For education & testing

Stock Chart & Livechat on website. For education & testing - GitHub - act99/stock-frontend: Stock Chart & Livechat on website. For education & testing

github.com