제목: 키움 OpenAPI 실시간 데이터 처리 — OnReceiveRealData, FID, DisconnectRealData C# 예제
안녕하세요! 조회 요청과 데이터 수신까지 다뤘으니, 이제 마지막 퍼즐인 실시간 시세 데이터를 정리할 차례입니다. 조회는 내가 요청해야 응답이 오지만, 실시간은 한번 등록하면 시세가 변할 때마다 자동으로 데이터가 흘러들어오는 구조예요. 체감이 완전히 다릅니다!
실시간 시세가 수신될 때마다 종목 단위로 이 이벤트가 발생합니다. 조회(CommRqData)로 종목을 요청하면 자동으로 실시간 등록이 되고, 이후 해당 종목의 체결, 호가 등의 변동이 생길 때마다 이벤트가 호출돼요.
sCode → 종목코드 (조회 시 사용한 코드 그대로, _NX/_AL 포함)sRealType → 실시간 타입 ("주식체결", "주식호가잔량" 등)sRealData → 실시간 데이터 전문 (직접 사용 불가)// 의사 코드
void OnReceiveRealData(string sCode, string sRealType, string sRealData)
{
if (sRealType == "주식체결")
// → GetCommRealData()로 현재가, 거래량 등 추출
if (sRealType == "주식호가잔량")
// → GetCommRealData()로 호가/잔량 데이터 추출
// sRealData는 직접 파싱하지 말고, 반드시 GetCommRealData() 사용!
}
실시간 데이터에서 원하는 값을 추출하는 함수예요. 조회의 GetCommData()가 항목 이름(문자열)을 쓰는 것과 달리, 실시간은 FID(Field ID, 숫자)를 사용합니다.
strCode → 종목코드nFid → 실시간 타입에 포함된 FID 번호10 → 현재가11 → 전일대비12 → 등락율13 → 누적거래량15 → 거래량20 → 체결시간228 → 체결강도// 의사 코드 — 주식체결 실시간 데이터
if (sRealType == "주식체결")
{
현재가 = GetCommRealData(sCode, 10);
전일대비 = GetCommRealData(sCode, 11);
등락율 = GetCommRealData(sCode, 12);
누적거래량 = GetCommRealData(sCode, 13);
체결시간 = GetCommRealData(sCode, 20);
체결강도 = GetCommRealData(sCode, 228);
}
여기서 한 가지 팁! 조회의 GetCommData()는 "현재가" 같은 문자열을 쓰지만, 실시간의 GetCommRealData()는 10 같은 숫자(FID)를 씁니다. 헷갈리기 쉬우니 꼭 구분해두세요.
실시간 수신을 더 이상 원하지 않을 때, 화면번호 단위로 실시간 등록을 해제하는 함수입니다. 해당 화면번호에 등록된 모든 종목의 실시간 수신이 중단돼요.
sScnNo → 실시간 해제할 화면번호 (조회 시 사용했던 4자리)// 의사 코드
// 화면번호 "1001"로 조회한 종목들의 실시간 해제
DisconnectRealData("1001");
// 주의: 같은 종목이 다른 화면번호로도 등록되어 있으면
// 그쪽 실시간은 계속 수신됩니다.
// 예) "1001"로 005930 조회, "1002"로도 005930 조회한 경우
// DisconnectRealData("1001") 해도 "1002" 쪽은 유지
지금까지 다룬 조회와 실시간의 차이를 한눈에 정리하면 이렇습니다.
CommRqData()OnReceiveTrDataGetCommData("항목이름")OnReceiveRealDataGetCommRealData(FID숫자)DisconnectRealData(화면번호)종목을 조회하면 자동으로 실시간 등록이 되고, 체결이 발생할 때마다 로그에 찍히는 예제입니다. 실시간 해제 버튼도 넣었어요. 폼에는 axKHOpenAPI1 컨트롤만 올려둔 상태입니다.
using AxKHOpenAPILib;
using System;
using System.Drawing;
using System.Windows.Forms;
namespace KiwoomRealTimeDemo
{
public partial class MainForm : Form
{
private Button btnLogin, btnRequest, btnDisconnect;
private TextBox txtCode, txtLog;
private Label lblStatus, lblRealCount;
private string currentScrNo = "1001";
private int realTickCount = 0;
public MainForm()
{
InitializeComponent();
CreateControls();
axKHOpenAPI1.OnEventConnect += OnEventConnect;
axKHOpenAPI1.OnReceiveTrData += OnReceiveTrData;
axKHOpenAPI1.OnReceiveRealData += OnReceiveRealData;
}
private void CreateControls()
{
btnLogin = new Button { Text = "로그인", Location = new Point(12, 12), Size = new Size(80, 30) };
btnLogin.Click += (s, e) => axKHOpenAPI1.CommConnect();
lblStatus = new Label { Text = "대기중...", Location = new Point(100, 18), AutoSize = true };
txtCode = new TextBox { Text = "005930", Location = new Point(12, 55), Size = new Size(100, 22) };
btnRequest = new Button { Text = "조회+실시간", Location = new Point(120, 53), Size = new Size(100, 26) };
btnRequest.Click += (s, e) => RequestWithRealTime();
btnDisconnect = new Button { Text = "실시간 해제", Location = new Point(230, 53), Size = new Size(100, 26) };
btnDisconnect.Click += (s, e) =>
{
axKHOpenAPI1.DisconnectRealData(currentScrNo);
AppendLog($"[해제] 화면번호 {currentScrNo} 실시간 등록 해제");
};
lblRealCount = new Label
{
Text = "실시간 수신: 0건",
Location = new Point(340, 57), AutoSize = true,
ForeColor = Color.Gray
};
txtLog = new TextBox
{
Multiline = true, ReadOnly = true,
Location = new Point(12, 90), Size = new Size(460, 260),
ScrollBars = ScrollBars.Vertical
};
Controls.AddRange(new Control[] {
btnLogin, lblStatus, txtCode, btnRequest,
btnDisconnect, lblRealCount, txtLog
});
}
// ── 조회 요청 (실시간 자동 등록) ──
private void RequestWithRealTime()
{
realTickCount = 0;
axKHOpenAPI1.SetInputValue("종목코드", txtCode.Text.Trim());
axKHOpenAPI1.CommRqData("주식기본정보", "opt10001", 0, currentScrNo);
AppendLog($"[조회] {txtCode.Text.Trim()} 요청 (화면번호:{currentScrNo})");
}
// ── 로그인 ──
private void OnEventConnect(object sender, _DKHOpenAPIEvents_OnEventConnectEvent e)
{
lblStatus.Text = e.nErrCode == 0 ? "로그인 성공!" : $"실패({e.nErrCode})";
}
// ── 조회 데이터 수신 (1회) ──
private void OnReceiveTrData(object sender, _DKHOpenAPIEvents_OnReceiveTrDataEvent e)
{
if (e.sRQName == "주식기본정보")
{
string name = axKHOpenAPI1.GetCommData(e.sTrCode, e.sRQName, 0, "종목명").Trim();
string price = axKHOpenAPI1.GetCommData(e.sTrCode, e.sRQName, 0, "현재가").Trim();
AppendLog($"[조회결과] {name} | 현재가:{price}");
AppendLog("[실시간] 등록 완료! 체결 데이터를 수신합니다...");
}
}
// ── 실시간 데이터 수신 (시세 변동마다 반복) ──
private void OnReceiveRealData(object sender, _DKHOpenAPIEvents_OnReceiveRealDataEvent e)
{
if (e.sRealType == "주식체결")
{
string time = axKHOpenAPI1.GetCommRealData(e.sRealKey, 20); // 체결시간
string price = axKHOpenAPI1.GetCommRealData(e.sRealKey, 10); // 현재가
string diff = axKHOpenAPI1.GetCommRealData(e.sRealKey, 11); // 전일대비
string rate = axKHOpenAPI1.GetCommRealData(e.sRealKey, 12); // 등락율
string volume = axKHOpenAPI1.GetCommRealData(e.sRealKey, 15); // 거래량
string strength = axKHOpenAPI1.GetCommRealData(e.sRealKey, 228); // 체결강도
realTickCount++;
lblRealCount.Text = $"실시간 수신: {realTickCount}건";
AppendLog($"[체결] {e.sRealKey} | {time} | {price}({diff}, {rate}%) | 거래량:{volume} | 강도:{strength}");
}
}
private void AppendLog(string msg)
{
txtLog.AppendText(msg + "\r\n");
}
}
}
if (e.sRealType == "주식체결")
{
string price = axKHOpenAPI1.GetCommRealData(e.sRealKey, 10); // 현재가
string volume = axKHOpenAPI1.GetCommRealData(e.sRealKey, 15); // 거래량
string strength = axKHOpenAPI1.GetCommRealData(e.sRealKey, 228); // 체결강도
}
OnReceiveRealData에서는 먼저 sRealType으로 어떤 종류의 데이터인지 구분합니다. "주식체결"이면 현재가, 거래량 등을 꺼내고, "주식호가잔량"이면 매수/매도 호가를 꺼내는 식이죠. 그리고 GetCommRealData()의 두 번째 인자에 FID 번호를 넣어 원하는 값을 가져옵니다. 각 실시간 타입별 FID 목록은 KOA Studio의 "실시간목록" 탭에서 확인할 수 있어요.
axKHOpenAPI1.DisconnectRealData(currentScrNo);
// currentScrNo = "1001" → 이 화면번호로 등록된 실시간 전부 해제
실시간 수신이 더 이상 필요 없을 때 호출합니다. 포인트는 화면번호 단위라는 점이에요. 조회할 때 사용한 화면번호를 그대로 넘기면 됩니다. 만약 같은 종목을 다른 화면번호로도 등록해뒀다면 그쪽 실시간은 영향 없이 계속 수신돼요. 그래서 종목별로 화면번호를 체계적으로 관리하는 게 중요합니다.
| 키움 OpenAPI로 종목 스캐너 만들기 2 — 3 열 레이아웃 (0) | 2026.06.11 |
|---|---|
| 키움 OpenAPI로 종목 스캐너 만들기 1 — 프로젝트 골격 (0) | 2026.06.10 |
| 키움 OpenAPI 조회 데이터 수신 — GetCommData, GetRepeatCnt, 연속조회까지 C# 예제 (0) | 2026.06.08 |
| 키움 OpenAPI 조회 요청 함수 총정리 — SetInputValue, CommRqData, CommKwRqData C# 예제 (0) | 2026.06.05 |
| 키움 OpenAPI 조회 및 실시간 데이터 처리 — 대체거래소(NXT) 종목코드부터 C# 예제까지 (0) | 2026.06.04 |
댓글 영역