개요

네이버와 다음에서 국내 주식시장의 일자별 주가정보를 제공하고 있습니다. 모든 데이터를 한꺼번에 받을 수는 없고, 한 페이지에 열흘치씩 제공하는 데이터를 여러차례 받아와야 합니다. 첫 페이지에 최근 데이터가 들어있고, 쉬는 날은 건너뛰기 때문에 특정 일자의 데이터가 몇 페이지에 들어있는지 알 수가 없습니다.

따라서, 특정 일자의 데이터가 몇 페이지에 들어있는지 계산하기 위한 산술식을 도출하고, 이를 함수로 만들어가는 과정을 아래와 같이 정리해 보았습니다.

데이터 확보

네이버에서 제공하는 가장 오래된 데이터인 1996년 06월까지 약 25년간 총 6,400여건의 데이터를 모두 가져와 각 데이터가 몇 페이지에 있었는지를 기록합니다.

def partition(line: str, n: int) -> t.Generator[list[str], None, None]:
    for i in range(0, len(line), n):
        yield line[i:i + n]

def parse(text: str) -> t.Generator[list[dict], None, None]:
    bs = BeautifulSoup(text, 'html.parser')

    values = [span.text for span in bs.findAll('span', class_='tah')]
    values = list(map(lambda v: v.strip().replace(',', ''), values))
    values = [int(v) if v.isnumeric() else v for v in values]

    # ['date', 'close', 'delta', 'open', 'high', 'low', 'volume']
    for row in partition(values, 7):
        d = datetime.strptime(row[0], '%Y.%m.%d')
        yield {
            'date': row[0]
        }

symbol = '015760'
result = []
for page in range(1, 643):
    r = requests.get(URL, 
                     params={'code': symbol, 'page': page}, 
                     headers=HEADERS)

    for item in parse(r.text):
        item['page'] = page
        item['delta'] = (datetime.today() - item['date']).days
        result.append(item)

for item in result:
    date, delta, page = item.values()
    print(f'{date}\t{delta}\t{page}')

회귀분석

출력된 결과를 Excel에 붙여넣고, 독립변수에 일자를, 종속변수에 페이지 번호를 넣어 회귀분석(Regression)을 수행합니다. Y절편과 기울기값을 알아낼 수 있습니다.

  • Y절편 : -0.329523068666276
  • 기울기 : 0.0677815661631966

Excel

함수 작성

아래의 함수를 통해 원하는 날짜의 데이터가 몇 페이지에 나오는지 계산할 수 있습니다.

def calc_page(target_date: typing.Union[datetime, str]) -> int:
    if isinstance(str, target_date):
        target_date = datetime.fromisoformat(target_date)

    Y1 = -0.329523068666276
    M = 0.0677815661631966
    delta = (datetime.today() - target_date).days
    
    return max(1, round(delta * M + Y1))

검증

전체 데이터를 대상으로 산출한 계산의 정확도는 51.8%에 불과하나, 잘못된 계산결과는 실제 데이터가 포함된 직전 페이지 번호이기 때문에, 한 페이지만 버리고 다음 페이지로 넘어가면 원하는 데이터를 찾아낼 수 있습니다.

assert 1 == calc_page('2022-02-15')
assert 100 == calc_page('2018-02-02')
assert 200 == calc_page('2014-01-10')
assert 300 == calc_page('2010-01-04')
assert 400 == calc_page('2005-12-22')
assert 500 == calc_page('2001-12-05')
assert 600 == calc_page('1997-11-22')

결론

사실 전 종목의 모든 데이터를 미리 로컬의 데이터베이스에 저장해 놓고 쿼리해 사용하고 있지만, 때로는 원격의 데이터 소스를 곧바로 활용하는 라이브러리도 필요하여 위와 같은 접근 방법을 소개해 보았습니다. yHistory (Github)에 구현되어 있으니 참고되시길 바랍니다.