Act99 기술블로그

[React] 직접 주가 캔들 차트 만들기6 - 볼린저 밴드 만들기 (SVG 연습용), (차트라이브러리 x) 본문

개발팁저장소/react

[React] 직접 주가 캔들 차트 만들기6 - 볼린저 밴드 만들기 (SVG 연습용), (차트라이브러리 x)

Act99 2021. 12. 1. 21:22

다음은 볼린저 밴드를 만들 차례이다.

볼린저 밴드란 존 볼린저의 주가 기술적 분석 도구이며, 이동평균선을 추세중심선으로 사용하고, 상하한 변동폭은 추세중심선의 표준편차로 계산한 밴드이다.

 

볼린저 밴드의 상한선: 20일 이평선 값 + ( 20일 동안의 주가 표준편차 값 ) * 2
볼린저 밴드의 하한선: 20일 이평선 값 - ( 20일 동안의 주가 표준편차 값 ) * 2

볼린저 밴드 구름대 형성 -> 상한선과 하한선 갭 =>  (상한선 – 하한선) / 중심선 이다.

 

이를 이용해 볼린저 밴드를 만들 것이다.

 

먼저 20일간의 주가 표준편차 값을 구해야 한다.

 

** 밑그림**

 

평균값

clo20ArrayBol = clo20Array.slice(index, (index+20)) -> 20개씩 추출

clo20ArrayBolTotal = clo20ArrayBol.reduce((a,b) => a+b) -> 배열들을 더함

 

clo20Average = clo20ArrayBolTotal / 20 -> 평균값

 

분산값

const gap:[] = [];

const calculate = () => gap.push(clo20ArrayBol.map((item) => item - col20Average))

calcuate()

console.log(gap) => 평균을 뺀 값들

gap.map((item) => item ** 2) => 제곱한 값들

const variance =  gap.reduce((a,b) => a+b) / 19  => (제곱한 값들을 더한값) /(20-1)  => 분산

 

const standartdDeviation = Math.sqrt(variance) => 표준편차 = 분산의 제곱근

****

 

여기까지 식을 구해놨다.

다음 적용할 차례이다.

 

  // 표준편차 구하는 식
  
  const bolUp = () => {
    let dummyLength = 0;
    const clo20ArrayBol: number[][] = [];
    const clo20Average: number[] = [];
    const gap: number[][] = [];
    const variance: number[] = [];
    const standardDeviation: number[] = [];
    for (let i = 0; i < stockArray.length; i++) {
      const a = clo20Array.slice(i, i + 20);

      if (a.length > 19) {
        clo20ArrayBol.push(a);
      } else {
        clo20ArrayBol.push([
          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        ]);
      }
      // [0000000] 이걸 넣은 이유는 데이터가 부족하기 때문이다.
      clo20Average.push(clo20ArrayBol[i].reduce((a, b) => a + b) / 20);
    }
    const calculate = () => {
      gap.push();
      for (let i = 0; i < stockArray.length; i++) {
        gap.push(
          clo20ArrayBol[i].map((item) => Math.abs(item - clo20Average[i]) ** 2)
        );
        variance.push(gap[i].reduce((a, b) => a + b) / 19);
        // 편의상 round로 반올림 시키겠다.
        standardDeviation.push(Math.round(Math.sqrt(variance[i])));
      }
    };
    calculate();
    // *************************************************
    // ** 아래 for 문은 나중에 real data 를 이용하면 삭제해도 되는 부분!!!
    // *************************************************
    for (let i = 0; i < standardDeviation.length; i++) {
      if (standardDeviation[i] === 0) {
        standardDeviation.splice(i, 1);
        dummyLength++;
        i--;
      }
    }
        for (let i = 0; i < dummyLength; i++) {
      standardDeviation.unshift(0);
    }
    // *************************************************
    // *************************************************


    console.log(dummyLength);
    console.log(stockArray);
    console.log(standardDeviation);
  };

 

원래 unshift 로 [0,0,0,0,0...] 값을 뒤에 추가하려했는데, 데이터 변질이 일어났다.

데이터 부족으로 일어나는 현상이니 넘어갔다.

(실제 데이터를 넣는다면 [0,0,0,0,0....] 이 필요 없을 것이며, 이 역시 구현 시켜놓았다.)

 

 

마무리로 볼린저밴더 상한선과 하한선을 구현시켰다.

 

  // ** 볼린저밴더
  // 표준편차
  let dummyLength = 0;
  const standardDeviation: number[] = [];
  const bolUp = () => {
    const clo20ArrayBol: number[][] = [];
    const clo20Average: number[] = [];
    const gap: number[][] = [];
    const variance: number[] = [];

    for (let i = 0; i < stockArray.length; i++) {
      const a = clo20Array.slice(i, i + 20);

      if (a.length > 19) {
        clo20ArrayBol.push(a);
      } else {
        clo20ArrayBol.push([
          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        ]);
      }
      // [0000000] 이걸 넣은 이유는 데이터가 부족하기 때문이다.
      clo20Average.push(clo20ArrayBol[i].reduce((a, b) => a + b) / 20);
    }
    const calculate = () => {
      gap.push();
      for (let i = 0; i < stockArray.length; i++) {
        gap.push(
          clo20ArrayBol[i].map((item) => Math.abs(item - clo20Average[i]) ** 2)
        );
        variance.push(gap[i].reduce((a, b) => a + b) / 19);
        // 편의상 round로 반올림 시키겠다.
        standardDeviation.push(Math.round(Math.sqrt(variance[i])));
      }
    };
    calculate();
    // *************************************************
    // ** 아래 for 문은 나중에 real data 를 이용하면 삭제해도 되는 부분!!!
    // *************************************************
    for (let i = 0; i < standardDeviation.length; i++) {
      if (standardDeviation[i] === 0) {
        standardDeviation.splice(i, 1);
        dummyLength++;
        i--;
      }
    }
    for (let i = 0; i < dummyLength; i++) {
      standardDeviation.unshift(0);
    }
    // *************************************************
    // *************************************************

    console.log(dummyLength);
    console.log(stockArray);
    console.log(standardDeviation);
  };

  bolUp();
  const dummyClo20Array: number[] = [];

  const bollingerArray: number[][] = [];
  const caculateBol = () => {
    // *************************************************
    // ** 아래 for 문은 나중에 real data 를 이용하면 삭제해도 되는 부분!!!
    // *************************************************
    for (let i = 0; i < clo20Array.length - 19; i++) {
      dummyClo20Array.push(clo20Array[i + 19]);
    }
    for (let i = 0; i < dummyLength; i++) {
      dummyClo20Array.unshift(0);
    }
    // *************************************************
    // *************************************************
    for (let i = 0; i < clo20Array.length; i++) {
      bollingerArray.push([
        dummyClo20Array[i] + standardDeviation[i] * 2,
        dummyClo20Array[i] - standardDeviation[i] * 2,
      ]);
    }
  };
  caculateBol();

  console.log(bollingerArray);
  // ** 볼린저 끝!

 

다음으로 차트 구현을 했다.

 

// 캔들차트로 데이터를 불러온 후.....



                {bolUpper[0] != bolUpper[1] && bollingerUpper[index][0] != 0 ? (
                  <line
                    stroke="blue"
                    x1={x + (barPlothWidth - sidePadding) / 2}
                    x2={xX + (barPlothWidth - sidePadding) / 2}
                    y1={yAxisLength - scaleY(bolUpper[0])}
                    y2={yAxisLength - scaleY(bolUpper[1])}
                  />
                ) : null}
                {bolLower[0] != bolLower[1] && bollingerUpper[index][0] != 0 ? (
                  <line
                    stroke="blue"
                    x1={x + (barPlothWidth - sidePadding) / 2}
                    x2={xX + (barPlothWidth - sidePadding) / 2}
                    y1={yAxisLength - scaleY(bolLower[0])}
                    y2={yAxisLength - scaleY(bolLower[1])}
                  />
                ) : null}

 

결과물 (볼린저밴드-파란색)

 

완성

 

이제는 코드정리를 할 차례이다. Redux를 이용해 변수들을 최소화시켜주고

모든 차트를 구성하는 컴퍼넌트를 각각의 tsx 파일로 변경시켜줄 예정이다.

 

볼린저 버튼 기능을 만들고, 주식데이터를 더 끌고와 라우터로 검색기능 구현까지 해야하며,

채팅기능까지 만들면 된다.