최근 AI업계에서 핫한 주제 중 하나로 MCP(Model Context Protocol)라는 규격이 있다.

그동안 AI는 두뇌만 있고, 손발이 없는 형국이었는 데, 이제 AI에게 손발을 붙여주고, 두뇌와 손발 사이에 MCP규약을 통해서 통신을 하도록 해서 통합 자동화 시스템 구축이 가능해 진 것이다.

이렇게, AI의 손발 역할을 해 주는 소프트웨어를 기술적 용어로 'MCP 서버'라고 부른다.

MCP라는 규격이 발표된 지 채 1년도 지나지 않았는 데, 이미 수천개의 'MCP서버'가 발표되었다.

(https://www.pulsemcp.com/)

 

아직까지는 대부분의 MCP서버가 소프트웨어 개발에 필요한 작업을 수행하는 도구들이다.

그런데, 이제 소프트웨어 개발 범주를 넘어서 날씨 검색, 티켓 예약등 온라인으로 수행 가능한 여러 방면의 작업으로 확장되고 있다.

 

그런데... 이제 금융 쪽으로도 확장되고 있다.

https://www.pulsemcp.com/servers/dragon1086-kospi-kosdaq-stock

 

KOSPI/KOSDAQ Stock Data MCP Server by Sangrok Mun | PulseMCP

MCP (Model Context Protocol) Server. Integrates with pykrx to provide real-time access to KOSPI and KOSDAQ stock market data, offering tools for retrieving ticker symbols, OHLCV data, market capitalization, fundamental metrics, and trading volumes.

www.pulsemcp.com

 

기능 설명 : 코스피/코스닥 주식 시장 데이터에 실시간으로 접근해서, 종목코드/일일 가격정보/시가총액/재무지표/거래량등의 정보를 제공.

 

AI가 실시간으로 한국 주식 시장 정보를 검색할 수 있도록 도와주는 도구(MCP서버)인 것이다.

 

한국 주식시장만 있는 게 아니다.

미국 기업 재무 정보 도구 : https://www.pulsemcp.com/servers/financial-datasets

미국 재무부 발표 매크로 정보 도구 : https://www.pulsemcp.com/servers/quantgeekdev-fiscal-data

암호 화폐 시장 정보 도구 : https://www.pulsemcp.com/servers/longmans-coin-api

중국 주식 시장 정보 도구 : https://www.pulsemcp.com/servers/ttjslbz001-akshare

 

이제 엑셀이나 프로그래밍을 하지 않아도, AI에게 '코스피 시총 상위 100위 안에 드는 대형주 종목 중 최근 20 영업일 거래 금액이 가장 적은 소외주 종목 10개를 알려줘'라고 한글로 명령하면 (엑셀이나 여타 데이터 분석 작업없이) AI가 알려주는 시대가 올 수도 있다는 의미이다.

 

아직 직접 사용해 보지 않아서, 실제로 이렇게 제대로 작동하는 지 확인해 보지는 못했지만, MCP 규약이 발표된 지 1년도 채 지나지 않은 현 시점에 AI에 금융 정보 도구를 장착하려는 수많은 시도가 출현한다는 사실이 주목할 만하다.

 

유명 코딩 유튜버의 MCP 소개 영상도 예제가 AI에 주식 매매 도구 장착하기 이다.

https://www.youtube.com/watch?v=EswVjHZMn74

 

시간이 좀 더 흐르면 AI에 가격 정보뿐만 아니라, 기업 재무 정보 도구, 매매 도구까지 장착해서, AI에게 투자 전략을 설명하면, AI가 알아서 실행해 주는 시대가 올 지도 모르겠다.

(소프트웨어 개발 분야의 경우 '바이브 코딩'이라고 해서 AI에게 말로 설명해서 개발하는 시대가 시작되었는 데, 투자 업계에도 이렇게 바뀔 수 있다.)

 

주식 시장은 이미 자동 매매 프로그램끼리의 전쟁터인데, 그것은 데이터 분석과 프로그래밍이 가능한 일부 사람들 간의 경쟁이었다면, 이제는 AI에게 투자 전략을 설명할 수 있는 모든 사람이 다 달려들테니까 더욱 피튀기는 시대가 될 것 같다.

 

 

 

 

모니시 파브라이는 투자는 극도의 인내심이 필요하며, 투자자의 매매 활동은 수익에 도움이 안 되며, 오히려 수익을 까먹는 경향이 있다는 설명을 한다.

그 근거로 피델리티의 통계를 인용하는 데,  고객 계좌 중 수익율이 가장 높은 10%는 대부분 휴면계좌이거나 계좌의 존재를 잊어버린 죽은 계좌 이었다고 한다.

 

앙드레 코스톨라니가 우량주 매수 후 수면제 먹고 2년 간 자고 일어나면 수익이 나 있을 것이라고 했던 발언과 일맥상통한다.

 

말은 쉬운 데 실천하기는 어려운 것 같다.

극도의 인내심이라는 게 누구나 가지고 있는 것은 아닌 듯.

 

https://www.youtube.com/watch?v=hc5IJz8PAxM

 

Julia언어로 '상장 법인 정보'를 획득하는 기능을 작성해봤다.

 

소스 코드는 다음 함수 3개로 되어 있다.

- f상장_법인_정보() : KRX 웹사이트에서 상장 법인 정보를 추출하는 함수.

- csv저장_법인_정보() : f상장_법인_정보()로 얻은 데이터를 CSV파일로 저장.

- csv읽기_법인_정보() : 저장된 CSV파일을 불러옴.

 

------------------------------

using Dates
using InlineStrings
using DataFrames
using TypedTables
using HTTP
using Gumbo
using Cascadia
using StringEncodings
using CSV


# KRX 웹사이트에서 상장 법인 정보를 얻는 함수.
function f상장_법인_정보()::Table
    상장_법인_정보 = DataFrame(
        종목코드=String7[], # 종목코드는 길이가 일정하므로, 고정폭 문자열 자료형 사용.
        회사명=String[],
        업종=String[],
        주요제품=String[],
        상장일=Date[],
        결산월=UInt8[])

    # KRX 상장 법인 정보 URL
    url = "https://kind.krx.co.kr/corpgeneral/corpList.do?method=download&searchType=13"
    응답값 = HTTP.get(url)
    응답_문자열 = StringEncodings.decode(응답값.body, "EUC-KR") # EUC-KR인코딩을 UTF-8인코딩으로 변환

    # Gumbo.jl을 이용해서 HTML 파싱.
    문서 = parsehtml(응답_문자열)

    # Cascadia.jl을 사용해서 테이블의 행을 추출.
    rows = eachmatch(Selector("body > table > tbody > tr"), 문서.root)

    # 각각의 행(tr)에서 정보를 추출하는 반복문.
    for tr in rows
        cols = eachmatch(Selector("td"), tr)

        회사명 = ""
        종목코드 = ""
        업종 = ""
        주요제품 = ""
        상장일 = Date(0)
        결산월 = 0

        for (열, td) in enumerate(cols)
            문자열 = strip(text(td))  # 공백 문자 제거

            if 열 == 1
                회사명 = 문자열
            elseif 열 == 2
                종목코드 = 문자열
            elseif 열 == 3
                업종 = 문자열
            elseif 열 == 4
                주요제품 = 문자열
            elseif 열 == 5
                try
                    상장일 = Date(문자열, "yyyy-mm-dd")
                catch e
                    println("상장일 에러 : $(종목코드) '$문자열'")
                end
            elseif 열 == 6
                결산월 = tryparse(UInt8, match(r"\d+", 문자열).match)
            end
        end

        if !isempty(종목코드) && !isempty(회사명) && !isempty(업종) && 상장일 != Date(0)
            push!(상장_법인_정보, Dict(
                :종목코드 => 종목코드,
                :회사명 => 회사명,
                :업종 => 업종,
                :주요제품 => 주요제품,
                :상장일 => 상장일,
                :결산월 => 결산월))
        end
    end

    # println("행 수량 : $(length(rows))")
    println("법인정보 수량 : $(nrow(상장_법인_정보))")

    # Type-stable TypedTables.jl형태로 반환.
    # 어쩌면 그냥 DataFrame을 그대로 쓰는 게 나을런지도.
    return Table(상장_법인_정보)
end

function csv저장_법인_정보()
    CSV.write("krx_ticker.csv", f상장_법인_정보())
end

function csv읽기_법인_정보()::Table
    return CSV.read("krx_ticker.csv", Table, types=Dict(1 => String, 5 => Date, 6 => UInt8))
end

# f상장_법인_정보()
# csv저장_법인_정보()
# csv읽기_법인_정보()