Trading & Coding

[채권 1] K-Bond 메신저 장외호가 DB 쌓기

minstack 2025. 6. 27. 00:05

조심스럽긴 하다

채권시장은 21세기에도 여전히
우수한 기술력을 자랑하는 플랫폼인
'메신저'에 1200명이 한 방에 모여
돗때기 시장판 마냥 조용한 고성이 오고간다.
 
실시간으로 호가가 뒤섞여 정신이 없다.
오늘이 지나면 그 호가는 사라진다.
분석이 안 된다.
 
그래서 할 수 있을지 없을지도 모르겠지만
일단 들이박아본다.
 
K-Bond 호가분석 시스템 개발.
오늘은 일단 무식하게,
호가를 전부 DB에 쑤셔넣는 것부터.


1. 문자열 분석: regex로 기본구조 발라내기

홍길동 (11:11:11) : 25-3 58- (A사 B부 1234-5678)
김철수 (11:15:20) : ㅎㅈ [C부 2345-6789]
bgc 임꺽정 (14:23:22) 26.3.5(목) 우금캐510-1 (민평 2.617%/끝.82/AA-) 민평 팔자 2.629 (채권부 555-4444)

 
메신저로 실시간 들어오는 문자열.
규칙이 있는 듯하면서도 없다.
하지만 일단 확실히 있는 규칙부터 턴다.

  • 발화자 (broker): 홍길동
    이름으로 시작한다. 대부분 세글자이지만,
    아닐수도 있다.
  • 시간 (talk_time): [공백](HH:MM:SS)[공백]:[공백]
  • 본문 (content): 25-3 58-
    대충 2025년에 3번째로 발행한 5년만기 국채
    ytm 2.58% (앞자리 2는 다 아니까 생략)
    팔자 (-) (사자는 +)
    필요로하는 핵심 메시지이다.
  • 뒷부분 연락처 (footer)
    보통 괄호나 대괄호로 끝남.
    전화할거 아니니까 별로 필요없음.

공략법

앞쪽부터 regex 회칼로 고정규칙 파트를 식별.
broker, talk_time, main_msg로 해체한다.
 
main_msg에서 다시 뒷부분 연락처 파트
지느러미 꼬리에 regex 회칼을 쑤셔넣고
footer로 해체한다.
 
괄호 나온다고 무조건 해체하면,
가운데 꼭 필요한 
몸통을 반토막 내버리는 참사가 발생. 주의. 
 

def is_system_message(line: str) -> bool:  
    # 입장/퇴장, 자동저장 메시지 제거  
    if "[자동 대화 저장 시작]" in line:  
        return True  
    if re.match(r".+님이 입장하셨습니다\.", line.strip()):  
        return True  
    if re.match(r".+님이 퇴장하였습니다\.", line.strip()):
        return True  
    return False

입장, 퇴장 등 쓰잘데기 없는 구문.
생선 대가리, 등 지느러미부터 쳐내듯이,
필터 함수로 먼저 깔끔하게 쳐낸다.
 


2. 정제 후 DataFrame으로 정리

parsed = []  
for m in messages:  
    p = parse_message(m, scrape_time=scrape_time_str)  
    if p:  
        # talk_time 문자열 → datetime.datetime 변환  
        hhmmss = datetime.strptime(p["talk_time"], "%H:%M:%S").time()  
        full_dt = datetime.combine(scrape_dt.date(), hhmmss)  
        p["talk_time"] = full_dt  
  
        p["raw_message"] = m  
        p["msg_hash"] = hashlib.md5(m.encode()).hexdigest()  # 고유 hash값 생성
        parsed.append(p)  
  
df = pd.DataFrame(parsed)  
df = df[[  
    "room", "broker", "talk_time", "content", "footer",  
    "scrape_time", "raw_message", "msg_hash"  
]]  
df["talk_time"] = df["talk_time"].apply(lambda x: x.strftime("%Y-%m-%d %H:%M:%S"))  
  
return df
  • parse_message() 에서 모든 정제를 마치고,
  • hashlib으로 각 메시지마다 고유 hash값 생성.
    토막낸 본문만으로 hash를 생성하면,
    시간대 다른 동일호가가 중복판정으로 누락 가능.
    꼭 raw_message로 hash 생성해야 함.
  • 향후 조회 용이성을 위해 '(HH:MM:SS)' 시간 칸에,
    날짜가 포함된 양식으로 갈아끼운다.
  • 중복 제거 + 정렬 + 저장을 위한 준비 완료.

3. MySQL DB 설계 후 쏟아붓기

MySQL에 통 하나 만든다.

  • 인덱스용 id
  • 원문 전체 보존용 raw_message
  • 중복 방지용 msg_hash UNIQUE

  • 만들어진 kbond_message 통에 정제한 DataFrame을 쏟아붓는다.
  • 중복은 INSERT IGNORE INTO 로 해결

결과 확인

 
11시 이후 메신저 내용을 SELECT 하면,
깔끔하게 해체되어 조회된다.
개꿀.
 


 
오늘은 갈치 등뼈정도 발라낸 수준.
젓가락만 들이대면 쏙 빠진다.
 
이제부터는 본문이다.
패턴이 있어 보이지만 없다.
가시를 하나씩 발라내는 장인정신 필요. 
 
 
장인정신엔 시간이 필요하여,
일단 다음 편은 FastAPI 기반 웹 조회 방법 쓸 계획.