요즘 C# 언어를 공부중인데 책으로 배우는 건 한계가 있어서 간단하게 C#을 이용해서 주식 클릭주문(번개주문)을 만들어 봤습니다
예제 코드에서 제공하는 주요 기능
- 현재가 조회 및 실시간 처리
- 미체결 조회 및 실시간 미체결 처리
- 매수/매도 주문 - 그림에 "매수주문" "매도주문" 컬럼을 클릭하면 선택된 행의 가격으로 매수 또는 매도 주문이 나갑니다
- 취소 주문 - 위 그림에서 "X" 컬럼은 이미 나간 미체결건을 취소합니다. 해당 가격에 나간 주문이 있어야만 취소 주문이 나갑니다.
- 종목검색 기능 - 거래소와 코스닥 종목을 검색할 수 있습니다.
주문의 경우 원하는 가격을 더블클릭 시 주문 확인창을 통해 주문 확인 후 처리 합니다.
아래는 메인 기능의 소스코드입니다. 전체 코드는 하단의 소스 프로젝트로 내려받을 수 있습니다.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
// PLUS OBJECT
using CPUTILLib;
using CPTRADELib;
using DSCBO1Lib;
using System.Diagnostics;
using System.Collections;
using System.Security.Permissions;
namespace PlusSampleApp
{
public partial class FormClickOrder : Form
{
enum PB_TYPE { ALL, CUR, HOGA, CONT }
enum ORDER_TYPE { BUY, SELL }
// 주문 항목 정보
class OrderItem
{
public int m_ordKey;
public int m_ordOrgKey;
public string m_sCode;
public string m_sText;
public int m_nAmt;
public int m_nContAmt;
public int m_nPrice;
public string m_sCredit;
public int m_nModAmt;
public ORDER_TYPE m_BStype;
public string m_sHogaFlag;
}
private CPUTILLib.CpCodeMgr m_cpCodeMgr;
private CPTRADELib.CpTdUtil m_cpTdUtil;
private DSCBO1Lib.StockCur m_cpStockCur;
private DSCBO1Lib.StockJpbid m_cpStockJpBid;
private DSCBO1Lib.CpConclusion m_cpConclusion;
private CpCommon m_cpCommon;
private Hashtable m_mapMst;
private Hashtable m_mapOrder;
private DataTable m_DataTable;
private string m_sCode;
// 컬럼 인덱스
int COL_SELLCANCEL = 0;
int COL_SELL = 1;
int COL_SELLHOGA = 2;
int COL_PRICE = 3;
int COL_BUYHOGA = 4;
int COL_BUY = 5;
int COL_BUYCANCEL = 6;
int ROW_SEL_START = 0;
int ROW_BUY_START = 11;
int ROW_CURPRICE = 10;
public FormClickOrder()
{
InitializeComponent();
m_cpCommon = new CpCommon();
m_cpTdUtil = new CPTRADELib.CpTdUtil();
m_cpCodeMgr = new CPUTILLib.CpCodeMgr();
// 현재가 실시간 객체 색성, 이벤트 함수 연동
m_cpStockCur = new DSCBO1Lib.StockCur();
m_cpStockCur.Received += new DSCBO1Lib._IDibEvents_ReceivedEventHandler(m_cpStockCur_Received);
m_cpStockJpBid = new DSCBO1Lib.StockJpbid();
m_cpStockJpBid.Received += new DSCBO1Lib._IDibEvents_ReceivedEventHandler(m_cpStockJpBid_Received);
m_sCode = "";
// 실시간 주문 체결
m_cpConclusion = new DSCBO1Lib.CpConclusion();
m_cpConclusion.Received += new DSCBO1Lib._IDibEvents_ReceivedEventHandler(m_cpConclusion_Received);
m_mapMst = new Hashtable();
m_mapOrder = new Hashtable();
// 화면 표시용 그리드에 넣기 위한 (row, col) 구조의 변수
m_DataTable = null;
}
private void Form1_Load(object sender, EventArgs e)
{
if (m_cpCommon.checkPlusStatus() == false)
{
//Debug.WriteLine("PLUS 실행 상태 점검필요");
MessageBox.Show("PLUS 실행 상태 점검필요", "PLUS 오류", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
InitGridTable();
m_edtCode.Text = "A005930";
//m_btnSearch_Click(null, null);
}
//////////////////////////////////////////////////////////////////////
/// 플러스 통신 요청 처리
//////////////////////////////////////////////////////////////////////
// 미체결 잔량 조회
private bool Rq5339(string sCode)
{
m_mapOrder.Clear();
CPTRADELib.CpTd5339 objRq = new CPTRADELib.CpTd5339();
objRq.SetInputValue(0, m_cpCommon.m_sAcc);
objRq.SetInputValue(1, m_cpCommon.m_sAccFlag);
// 종목코드
objRq.SetInputValue(3, sCode);
objRq.SetInputValue(4, "0"); // 주문구분 : 전체
objRq.SetInputValue(5, "1"); // 정렬 기준 - 역순
objRq.SetInputValue(6, "0"); // 주문종가구분 전체
objRq.SetInputValue(7, 20); // 요청 개수 - 최대 20개
while (true)
{
m_cpCommon.waitRqLimit(COMM_TYPE.ACC);
int nRet = objRq.BlockRequest();
if (false == m_cpCommon.checkRqError(objRq, nRet))
return false;
// 수신 개수
int nCnt = objRq.GetHeaderValue(5);
Debug.WriteLine("미체결 수신개수: " + nCnt);
for (int i = 0; i < nCnt; i++)
{
OrderItem item = new OrderItem();
item.m_ordKey = objRq.GetDataValue(1, i); // 주문 번호
item.m_ordOrgKey = objRq.GetDataValue(1, i); // 원주문번호
item.m_sCode = objRq.GetDataValue(3, i); // 종목코드
item.m_sText = objRq.GetDataValue(5, i); // 주문 내용
item.m_nAmt = objRq.GetDataValue(6, i); // 주문수량
item.m_nPrice = objRq.GetDataValue(7, i); // 주문단가
item.m_nContAmt = objRq.GetDataValue(8, i); //# 체결수량
item.m_sCredit = objRq.GetDataValue(9, i); // 신용구분
item.m_nModAmt = objRq.GetDataValue(11, i); // 정정취소 가능수량
string sFlag = objRq.GetDataValue(13, i); // 매매구분코드
if (sFlag == "1")
item.m_BStype = ORDER_TYPE.SELL;
else if (sFlag == "2")
item.m_BStype = ORDER_TYPE.BUY;
item.m_sHogaFlag = objRq.GetDataValue(21, i); // 주문호가구분코드
// 해당 종목인 경우만 추가 한다.
if (sCode != item.m_sCode)
continue;
// 가격별로 주문 수량 map 미리 생성 - 동일 가격에 주문 수량이 복수개 있을 수 있음.
m_mapOrder[item.m_ordKey] = item;
} //end of for
if (objRq.Continue == 0)
break;
}
foreach (DictionaryEntry item in m_mapOrder)
{
OrderItem data = (OrderItem)item.Value;
Debug.WriteLine("주문번호: {0}: 수량: {1} 가격: {2}", item.Key, data.m_nAmt, data.m_nPrice);
}
return true;
}
// 취소 주문 요청
private bool RqCancelOrder(int ordKey)
{
CPTRADELib.CpTd0314 objRq = new CPTRADELib.CpTd0314();
OrderItem data = (OrderItem)m_mapOrder[ordKey];
objRq.SetInputValue(1, ordKey); // 원주문 번호 - 정정을 하려는 주문 번호
objRq.SetInputValue(2, m_cpCommon.m_sAcc);
objRq.SetInputValue(3, m_cpCommon.m_sAccFlag);
objRq.SetInputValue(4, data.m_sCode); // 종목코드
objRq.SetInputValue(5, 0); // 정정 수량, 0 이면 잔량 취소임
m_cpCommon.waitRqLimit(COMM_TYPE.ACC);
int nRet = objRq.BlockRequest();
if (false == m_cpCommon.checkRqError(objRq, nRet))
return false;
return true;
}
// 매수/매도 주문 요청
private bool RqOrder(ORDER_TYPE ordType, string sCode, int nPrice, int nAmt)
{
CPTRADELib.CpTd0311 objRq = new CPTRADELib.CpTd0311();
if (ordType == ORDER_TYPE.SELL)
objRq.SetInputValue(0, "1"); // 1 매도 2 매수
if (ordType == ORDER_TYPE.BUY)
objRq.SetInputValue(0, "2"); // 1 매도 2 매수
objRq.SetInputValue(1, m_cpCommon.m_sAcc);
objRq.SetInputValue(2, m_cpCommon.m_sAccFlag);
objRq.SetInputValue(3, sCode); // 종목코드
objRq.SetInputValue(4, nAmt); // 수량
objRq.SetInputValue(5, nPrice); // 주문단가
objRq.SetInputValue(7, "0"); // 주문 조건 구분 코드, 0: 기본 1: IOC 2:FOK
objRq.SetInputValue(8, "01"); // 주문호가 구분코드 - 01: 보통 03 시장가 05 조건부지정가
m_cpCommon.waitRqLimit(COMM_TYPE.ACC);
int nRet = objRq.BlockRequest();
if (false == m_cpCommon.checkRqError(objRq, nRet))
return false;
return true;
}
// 주식 현재가 조회
private bool RqStockMst(string sCode)
{
string sName = m_cpCodeMgr.CodeToName(sCode);
Debug.WriteLine("종목 " + sCode + " " + sName);
DSCBO1Lib.StockMst objRq = new DSCBO1Lib.StockMst();
objRq.SetInputValue(0, sCode);
m_cpCommon.waitRqLimit(COMM_TYPE.SISE);
int nRet = objRq.BlockRequest();
if (false == m_cpCommon.checkRqError(objRq, nRet))
return false;
m_mapMst["시간"] = objRq.GetHeaderValue(4);
m_mapMst["시가"] = objRq.GetHeaderValue(13);
m_mapMst["고가"] = objRq.GetHeaderValue(14);
m_mapMst["저가"] = objRq.GetHeaderValue(15);
int nClose = objRq.GetHeaderValue(11);
int nDiff = objRq.GetHeaderValue(12);
int nBase = nClose - nDiff;
m_mapMst["대비율"] = 0;
if (nBase > 0)
{
m_mapMst["대비율"] = (float)(nDiff / (float)nBase) * 100;
}
m_mapMst["종가"] = nClose;
m_mapMst["대비"] = nDiff;
m_mapMst["기준가"] = nBase;
for (int i = 0; i < 10; i++)
{
string sKey = (i + 1).ToString();
m_mapMst[sKey + "_매도호가"] = objRq.GetDataValue(0, i);
m_mapMst[sKey + "_매수호가"] = objRq.GetDataValue(1, i);
m_mapMst[sKey + "_매도잔량"] = objRq.GetDataValue(2, i);
m_mapMst[sKey + "_매수잔량"] = objRq.GetDataValue(3, i);
}
foreach (DictionaryEntry item in m_mapMst)
{
Debug.WriteLine("{0}:{1}", item.Key, item.Value);
}
return true;
}
//////////////////////////////////////////////////////////////////////
/// 실시간 등록 처리
//////////////////////////////////////////////////////////////////////
// 실시간 시세 및 체결 등록
private void SBStockInfos(string sCode)
{
// 이전 sb cancel
SbCancel(m_sCode);
m_sCode = sCode;
// 주식 현재가 실시간 등록
m_cpStockCur.SetInputValue(0, sCode);
m_cpStockCur.Subscribe();
// 주식 10차 호가 실시간 등록
m_cpStockJpBid.SetInputValue(0, sCode);
m_cpStockJpBid.Subscribe();
// 주문 체결 실시간 등록
m_cpConclusion.Subscribe();
Debug.WriteLine("SB START CODE {0}", sCode);
}
// 실시간 시세 및 체결 등록 해지
private void SbCancel(string sCode)
{
if (sCode == "")
return;
m_cpStockCur.SetInputValue(0, sCode);
m_cpStockCur.Unsubscribe();
m_cpStockJpBid.SetInputValue(0, sCode);
m_cpStockJpBid.Unsubscribe();
m_cpConclusion.Unsubscribe();
m_sCode = "";
}
//////////////////////////////////////////////////////////////////////
/// 화면, 데이터 처리
//////////////////////////////////////////////////////////////////////
// 그리드 초기화 - 컬럼, 배경색상 등
void InitGridTable()
{
if (m_DataTable != null)
m_DataTable.Clear();
m_DataTable = new DataTable();
m_DataTable.Columns.Add("X");
m_DataTable.Columns.Add("매도주문");
m_DataTable.Columns.Add("매도잔량");
m_DataTable.Columns.Add("호가");
m_DataTable.Columns.Add("매수잔량");
m_DataTable.Columns.Add("매수주문");
m_DataTable.Columns.Add("x");
for (int i = 0; i < 21; i++)
m_DataTable.Rows.Add("", "", "", "", "", "", "");
m_HogaView.DataSource = m_DataTable;
m_HogaView.ColumnHeadersDefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleCenter;
m_HogaView.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill;
m_HogaView.AllowUserToResizeRows = false;
m_HogaView.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right;
m_HogaView.RowsDefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleRight;
m_HogaView.Refresh();
// 배경색 칠하기 - 매도잔량
for (int i = ROW_SEL_START; i < ROW_SEL_START + 10; i++)
m_HogaView[COL_SELLHOGA, i].Style.BackColor = Color.FromArgb(215, 233, 255);
// 배경색 칠하기 - 매도호가
for (int i = ROW_SEL_START; i < ROW_SEL_START + 10; i++)
m_HogaView[COL_PRICE, i].Style.BackColor = Color.FromArgb(215, 233, 255);
// 배경색 칠하기 - 매수잔량
for (int i = ROW_BUY_START; i < ROW_BUY_START + 10; i++)
m_HogaView[COL_BUYHOGA, i].Style.BackColor = Color.FromArgb(255, 227, 227);
// 배경색 칠하기 - 매수호가
for (int i = ROW_BUY_START; i < ROW_BUY_START + 10; i++)
m_HogaView[COL_PRICE, i].Style.BackColor = Color.FromArgb(255, 227, 227);
// 배경색 칠하기 - 현재가
m_HogaView[COL_SELLHOGA, ROW_CURPRICE].Style.BackColor = Color.White;
m_HogaView[COL_PRICE, ROW_CURPRICE].Style.BackColor = Color.White;
m_HogaView[COL_BUYHOGA, ROW_CURPRICE].Style.BackColor = Color.White;
// 매수주문, 매수취소 영역 배경색
m_HogaView.Columns[COL_BUY].DefaultCellStyle.BackColor = Color.FromArgb(254, 238, 238);
m_HogaView.Columns[COL_BUYCANCEL].DefaultCellStyle.BackColor = Color.FromArgb(254, 238, 238);
// 매도주문, 매도취소 영역 배경색
m_HogaView.Columns[COL_SELL].DefaultCellStyle.BackColor = Color.FromArgb(226, 239, 254);
m_HogaView.Columns[COL_SELLCANCEL].DefaultCellStyle.BackColor = Color.FromArgb(226, 239, 254);
m_HogaView.Font = new Font("Tahoma", 10, FontStyle.Regular);
//m_HogaView[COL_PRICE, 10].Style.Font = new Font("Tahoma", 10, FontStyle.Bold);
//m_HogaView[COL_BUYHOGA, 10].Style.Font = new Font("Tahoma", 10, FontStyle.Bold);
// 취소 컬럼 영역 사이즈 조절
m_HogaView.Columns[COL_SELLCANCEL].AutoSizeMode = DataGridViewAutoSizeColumnMode.None;
m_HogaView.Columns[COL_SELLCANCEL].Width = 30;
m_HogaView.Columns[COL_BUYCANCEL].AutoSizeMode = DataGridViewAutoSizeColumnMode.None;
m_HogaView.Columns[COL_BUYCANCEL].Width = 30;
// 왼쪽 커서 제거
m_HogaView.RowHeadersVisible = false;
}
// 그리드 초기화
// 종목 변경 시 큐 정보 클리어
private void clearQueue()
{
for (int i = ROW_SEL_START; i < ROW_SEL_START + 21; i++)
{
m_DataTable.Rows[i]["매도주문"] = "";
m_DataTable.Rows[i]["매수주문"] = "";
}
}
// 주어진 주문 유형, 주문 가격에 해당하는 미체결 주문 수량을 모두 찾아 합을 리턴한다.
private int getOrderPriceAmt(ORDER_TYPE type, int nPrice)
{
int nAmt = 0;
foreach (DictionaryEntry item in m_mapOrder)
{
OrderItem data = (OrderItem)item.Value;
if (type == data.m_BStype)
{
if (data.m_nPrice == nPrice)
nAmt += data.m_nAmt;
}
}
return nAmt;
}
// 가격에 해당하는 미체결 정보를 배열로 생성해서 리턴
private ArrayList getOrderKeyFromPrice(ORDER_TYPE type, int nPrice)
{
ArrayList list = new ArrayList();
foreach (DictionaryEntry item in m_mapOrder)
{
OrderItem data = (OrderItem)item.Value;
if (type == data.m_BStype)
{
if (data.m_nPrice == nPrice)
list.Add(data.m_ordKey);
}
}
return list;
}
// 그리드에 표출하기 위해 DataTable 에 내용 업데이트 한다.
private void setDataToQueue(PB_TYPE pbtype)
{
if (pbtype == PB_TYPE.ALL || pbtype == PB_TYPE.HOGA)
{
// 매도잔량 | 호가 채우기
for (int i = 0; i < 10; i++)
{
string sKey = (10 - i).ToString();
m_DataTable.Rows[ROW_SEL_START + i]["매도잔량"] = string.Format("{0:N0}", m_mapMst[sKey + "_매도잔량"]);
m_DataTable.Rows[ROW_SEL_START + i]["호가"] = string.Format("{0:N0}", m_mapMst[sKey + "_매도호가"]);
}
// 매수잔량 | 호가 채우기
for (int i = 0; i < 10; i++)
{
string sKey = (i + 1).ToString();
m_DataTable.Rows[ROW_BUY_START + i]["호가"] = string.Format("{0:N0}", m_mapMst[sKey + "_매수호가"]);
m_DataTable.Rows[ROW_BUY_START + i]["매수잔량"] = string.Format("{0:N0}", m_mapMst[sKey + "_매수잔량"]);
}
}
if (pbtype == PB_TYPE.ALL || pbtype == PB_TYPE.CUR)
{
// 현재가 채우기
m_DataTable.Rows[ROW_CURPRICE]["매도잔량"] = "현재가";
m_DataTable.Rows[ROW_CURPRICE]["호가"] = string.Format("{0:N0}", m_mapMst["종가"]);
string sDiff = string.Format("{0:N0}", m_mapMst["대비"]);
m_DataTable.Rows[ROW_CURPRICE]["매수잔량"] = sDiff;
sDiff = string.Format("{0:f2}%", m_mapMst["대비율"]);
m_DataTable.Rows[ROW_CURPRICE - 1]["매수잔량"] = sDiff;
// 현재가, 대비 색상처리
int nDiff = (int)m_mapMst["대비"];
Color clrDiff = Color.FromArgb(0, 0, 0);
if (nDiff > 0)
clrDiff = Color.FromArgb(255, 0, 0);
else if (nDiff < 0)
clrDiff = Color.FromArgb(0, 0, 255);
m_HogaView[COL_PRICE, ROW_CURPRICE].Style.ForeColor = clrDiff;
m_HogaView[COL_BUYHOGA, ROW_CURPRICE].Style.ForeColor = clrDiff;
m_HogaView[COL_BUYHOGA, ROW_CURPRICE - 1].Style.ForeColor = clrDiff;
}
// 미체결 주문 잔량을 가격 라인에 표시
if (pbtype == PB_TYPE.ALL || pbtype == PB_TYPE.CONT || pbtype == PB_TYPE.HOGA)
{
// 매도 미체결 수량 표시
for (int i = ROW_SEL_START; i < (ROW_SEL_START + 21); i++)
{
// 현재가 행은 미체결 표시 없음.
if (i == ROW_CURPRICE)
continue;
int nPrice = 0;
if (i < ROW_CURPRICE)
{
string sKey = (10 - i).ToString();
nPrice = (int)m_mapMst[sKey + "_매도호가"];
}
else if (i > ROW_CURPRICE)
{
string sKey = (i - ROW_CURPRICE).ToString();
nPrice = (int)m_mapMst[sKey + "_매수호가"];
}
int nAmtSell = getOrderPriceAmt(ORDER_TYPE.SELL, nPrice);
int nAmtBuy = getOrderPriceAmt(ORDER_TYPE.BUY, nPrice);
// 현재 가격에 매도 미체결이 있으면 미체결 합을 표시
if (nAmtSell ==0)
m_DataTable.Rows[i]["매도주문"] = "";
else
m_DataTable.Rows[i]["매도주문"] = nAmtSell;
if (nAmtBuy == 0)
m_DataTable.Rows[i]["매수주문"] = "";
else
m_DataTable.Rows[i]["매수주문"] = nAmtBuy;
}
}
m_HogaView.DataSource = m_DataTable;
m_HogaView.Refresh();
}
//////////////////////////////////////////////////////////////////////
/// PLUS 실시간 이벤트 처리
//////////////////////////////////////////////////////////////////////
// 실시간 호가 수신
private void m_cpStockJpBid_Received()
{
Debug.WriteLine("현재가 호가 PB 수신");
//m_mapMst["시간"] = m_cpStockJpBid.GetHeaderValue(3);
int nStart = 3;
for (int i = 0; i < 5; i++)
{
string sKey = (i + 1).ToString();
m_mapMst[sKey + "_매도호가"] = m_cpStockJpBid.GetHeaderValue(nStart++);
m_mapMst[sKey + "_매수호가"] = m_cpStockJpBid.GetHeaderValue(nStart++);
m_mapMst[sKey + "_매도잔량"] = m_cpStockJpBid.GetHeaderValue(nStart++);
m_mapMst[sKey + "_매수잔량"] = m_cpStockJpBid.GetHeaderValue(nStart++);
}
nStart = 27;
for (int i = 5; i < 10; i++)
{
string sKey = (i + 1).ToString();
m_mapMst[sKey + "_매도호가"] = m_cpStockJpBid.GetHeaderValue(nStart++);
m_mapMst[sKey + "_매수호가"] = m_cpStockJpBid.GetHeaderValue(nStart++);
m_mapMst[sKey + "_매도잔량"] = m_cpStockJpBid.GetHeaderValue(nStart++);
m_mapMst[sKey + "_매수잔량"] = m_cpStockJpBid.GetHeaderValue(nStart++);
}
setDataToQueue(PB_TYPE.HOGA);
}
// 실시간 시세체결 수신
private void m_cpStockCur_Received()
{
Debug.WriteLine("현재가 체결 PB 수신");
m_mapMst["시간"] = m_cpStockCur.GetHeaderValue(3);
m_mapMst["시가"] = m_cpStockCur.GetHeaderValue(4);
m_mapMst["고가"] = m_cpStockCur.GetHeaderValue(5);
m_mapMst["저가"] = m_cpStockCur.GetHeaderValue(6);
int nClose = m_cpStockCur.GetHeaderValue(13);
int nDiff = m_cpStockCur.GetHeaderValue(2);
int nBase = nClose - nDiff;
m_mapMst["대비율"] = 0;
if (nBase > 0)
{
m_mapMst["대비율"] = (float)(nDiff / (float)nBase) * 100;
}
m_mapMst["종가"] = nClose;
m_mapMst["대비"] = nDiff;
m_mapMst["기준가"] = nBase;
setDataToQueue(PB_TYPE.CUR);
}
// 실시간 주문 체결 수신
private void m_cpConclusion_Received()
{
Hashtable mapConclution = new Hashtable();
Debug.WriteLine("주문 체결 PB 수신");
int nContAmt = m_cpConclusion.GetHeaderValue(3); // 주문, 체결 수량
int nPrice = m_cpConclusion.GetHeaderValue(4); // 가격
int nOrdKey = m_cpConclusion.GetHeaderValue(5); //주문번호
int nOrdOrgKey = m_cpConclusion.GetHeaderValue(6); //원주문번호
string sConFlag = m_cpConclusion.GetHeaderValue(14); //체결 플래그 1 체결 2 확인...
// 기타 값들은 맵에 저장..
mapConclution["종목코드"] = m_cpConclusion.GetHeaderValue(9); //종목코드
mapConclution["매수매도"] = m_cpConclusion.GetHeaderValue(12); //매수/매도 구분 1 매도 2매수
mapConclution["정정취소"] = m_cpConclusion.GetHeaderValue(16); //정정/취소 구분코드 (1 정상, 2 정정 3 취소)
mapConclution["주문호가구분"] = m_cpConclusion.GetHeaderValue(18); //주문호가구분코드
mapConclution["주문조건구분"] = m_cpConclusion.GetHeaderValue(19); //주문조건구분코드
mapConclution["장부가"] = m_cpConclusion.GetHeaderValue(21); //장부가
mapConclution["매도가능"] = m_cpConclusion.GetHeaderValue(22); //매도가능수량
mapConclution["체결기준잔고"] = m_cpConclusion.GetHeaderValue(23); //체결기준잔고수량
// 현재 종목만 처리
if (m_sCode != (string)mapConclution["종목코드"])
return;
OrderItem data = null;
switch (sConFlag)
{
case "1" : // 체결
if (m_mapOrder.ContainsKey(nOrdKey) == false)
return;
data = (OrderItem)m_mapOrder[nOrdKey];
// 일부 체결 - 원주문에서 체결 수량만큼 뺀다.
if (data.m_nAmt - nContAmt > 0)
{
data.m_nAmt -= nContAmt;
data.m_nModAmt = data.m_nAmt;
data.m_nContAmt += nContAmt;
}
else // 전부 체결 - 원주문 제거
{
m_mapOrder.Remove(nOrdKey);
}
break;
case "2": // 확인 - 정정 또는 취소 확인
// 원주문이 있는 지 체크 한다. (무조건 원주문이 있어야 하지만, ioc, fok 는 예외)
if (m_mapOrder.ContainsKey(nOrdOrgKey) == false)
{
// IOC/FOK 의 경우 취소 주문을 낸적이 없어도 자동으로 취소 확인이 들어 온다.
if ((string)mapConclution["정정취소"] == "3")
m_mapOrder.Remove(nOrdKey);
return;
}
// 원주문을 찾아 처리
data = (OrderItem)m_mapOrder[nOrdOrgKey];
// 정정확인
if ((string)mapConclution["정정취소"] == "2")
{
// 일부 정정 : 기존 주문은 수량 조절, 새로운 미체결은 추가
if (data.m_nAmt - nContAmt > 0)
{
// 기존 미체결 수량 조정
data.m_nAmt -= nContAmt;
data.m_nModAmt = data.m_nAmt;
// 새로운 정정 가격으로 추가
OrderItem item1 = new OrderItem();
item1.m_ordKey = (int)nOrdKey;
item1.m_ordOrgKey = (int)nOrdOrgKey;
item1.m_sCode = (string)mapConclution["종목코드"];
//item.m_sText = objRq.GetDataValue(5, i); // 주문 내용
item1.m_nAmt = nContAmt; // 주문수량
item1.m_nPrice = (int)nPrice; // 주문단가
item1.m_nContAmt = 0; //# 체결수량
item1.m_nModAmt = nContAmt; // 정정취소 가능수량
item1.m_BStype = data.m_BStype;
item1.m_sHogaFlag = (string)mapConclution["주문호가구분"]; // 주문호가구분코드내용
m_mapOrder[item1.m_ordKey] = item1;
}
// 전체 정정 - 기존 주문은 제거하고, 새로운 정정 가격으로 추가
else
{
m_mapOrder.Remove(nOrdOrgKey);
// 새로운 정정 가격으로 추가
OrderItem item1 = new OrderItem();
item1.m_ordKey = (int)nOrdKey;
item1.m_ordOrgKey = (int)nOrdOrgKey;
item1.m_sCode = (string)mapConclution["종목코드"];
//item.m_sText = objRq.GetDataValue(5, i); // 주문 내용
item1.m_nAmt = nContAmt; // 주문수량
item1.m_nPrice = (int)nPrice; // 주문단가
item1.m_nContAmt = 0; //# 체결수량
item1.m_nModAmt = nContAmt; // 정정취소 가능수량
item1.m_BStype = data.m_BStype;
item1.m_sHogaFlag = (string)mapConclution["주문호가구분"]; // 주문호가구분코드내용
m_mapOrder[item1.m_ordKey] = item1;
}
}
// 취소확인 - 해당 원주문을 제거
else if ((string)mapConclution["정정취소"] == "3")
{
if (m_mapOrder.ContainsKey(nOrdOrgKey) == true)
{
m_mapOrder.Remove(nOrdOrgKey);
}
}
break;
case "3": // 거부
break;
case "4": // 접수
// 신규 매수/매도 주문만 처리
if ((string)mapConclution["정정취소"] != "1")
break;
// 신규 접수된 미체결 정보를 추가한다.
OrderItem item = new OrderItem();
item.m_ordKey = (int)nOrdKey;
item.m_ordOrgKey = (int)nOrdOrgKey;
item.m_sCode = (string)mapConclution["종목코드"];
//item.m_sText = objRq.GetDataValue(5, i); // 주문 내용
item.m_nAmt = (int)nContAmt; // 주문수량
item.m_nPrice = (int)nPrice; // 주문단가
item.m_nContAmt = 0; //# 체결수량
item.m_nModAmt = item.m_nAmt; // 정정취소 가능수량
if ((string)mapConclution["매수매도"] == "1")
item.m_BStype = ORDER_TYPE.SELL;
else if ((string)mapConclution["매수매도"] == "2")
item.m_BStype = ORDER_TYPE.BUY;
item.m_sHogaFlag = (string)mapConclution["주문호가구분"]; // 주문호가구분코드내용
m_mapOrder[item.m_ordKey] = item;
break;
}
// 미체결 정보 그리드에 업데이트
setDataToQueue(PB_TYPE.CONT);
}
//////////////////////////////////////////////////////////////////////
/// 화면 이벤트 처리
//////////////////////////////////////////////////////////////////////
// 종목코드가 변경 시 처리
private void m_edtCode_TextChanged(object sender, EventArgs e)
{
m_btnRetry_Click(null, null);
}
// 조회 버튼 클릭 시 처리
private void m_btnSearch_Click(object sender, EventArgs e)
{
StockCodeDlg dlg = new StockCodeDlg();
DialogResult result = dlg.ShowDialog();
if (result != DialogResult.OK)
return;
m_edtCode.Text = dlg.m_sRetCode;
}
// 그리드 더블클릭 처리
// 매도/매수주문 컬럼 --> 주어진 가격으로 주문
// 취소 컬럼 --> 주어진 가격에 미체결수량이 있으면 취소
private void m_HogaView_CellDoubleClick(object sender, DataGridViewCellEventArgs e)
{
Debug.WriteLine("더블클릭 이벤트 발생{0}:{1}", e.RowIndex, e.ColumnIndex);
if (e.ColumnIndex == COL_SELL || e.ColumnIndex == COL_BUY)
{
string sPrice = (string)m_HogaView[COL_PRICE, e.RowIndex].Value.ToString();
sPrice = sPrice.Replace(",", "");
if (sPrice.Length == 0)
return;
int nPrice = Convert.ToInt32(sPrice);
int nAmt = (int)m_editAmt.Value;
if (nPrice == 0)
return;
// 매도 주문 발생
if (e.ColumnIndex == COL_SELL)
{
string sAlert = string.Format("매도주문\n주문 가격: {0}\n주문수량: {1}\n주문처리 하시겠습니까?", nPrice, nAmt);
if (DialogResult.No == MessageBox.Show(sAlert, "주문확인", MessageBoxButtons.YesNo, MessageBoxIcon.Exclamation))
return;
RqOrder(ORDER_TYPE.SELL, m_sCode, nPrice, nAmt);
}
else if (e.ColumnIndex == COL_BUY)
{
string sAlert = string.Format("매수주문\n주문 가격: {0}\n주문수량: {1}\n주문처리 하시겠습니까?", nPrice, nAmt);
if (DialogResult.No == MessageBox.Show(sAlert, "주문확인", MessageBoxButtons.YesNo, MessageBoxIcon.Exclamation))
return;
RqOrder(ORDER_TYPE.BUY, m_sCode, nPrice, nAmt);
}
}
if (e.ColumnIndex == COL_SELLCANCEL || e.ColumnIndex == COL_BUYCANCEL)
{
string sPrice = (string)m_HogaView[COL_PRICE, e.RowIndex].Value.ToString();
sPrice = sPrice.Replace(",", "");
if (sPrice.Length == 0)
return;
int nPrice = Convert.ToInt32(sPrice);
// 매도 취소 발생
if (e.ColumnIndex == COL_SELLCANCEL)
{
Debug.WriteLine("매도 취소 주문, 가격{0}", nPrice);
ArrayList list = getOrderKeyFromPrice(ORDER_TYPE.SELL, nPrice);
foreach (object obj in list)
RqCancelOrder((int)obj);
}
else if (e.ColumnIndex == COL_BUYCANCEL)
{
Debug.WriteLine("매수 취소 주문, 가격{0}", nPrice);
ArrayList list = getOrderKeyFromPrice(ORDER_TYPE.BUY, nPrice);
foreach (object obj in list)
RqCancelOrder((int)obj);
}
}
}
private void m_btnRetry_Click(object sender, EventArgs e)
{
string sCode = m_edtCode.Text;
if (sCode.Length < 6)
return;
string sName = m_cpCodeMgr.CodeToName(sCode);
if (sName == "")
return;
m_stockName.Text = sName;
if (sCode.Length == 6)
{
sCode = 'A' + sCode;
}
// 그리드 초기화
clearQueue();
// 현재가 통신
RqStockMst(sCode);
// 미체결 통신
Rq5339(sCode);
// 가져온 데이터 화면에 표시
setDataToQueue(PB_TYPE.ALL);
// 실시간 정보 요청
SBStockInfos(sCode);
}
}
}
소스 전체를 원하시는 분은 아래 링크에서 내려 받을 수 있습니다.
소스코드 내려받기
※ 주의 사항 : 해당 예제는 C# 공부삼아 만든 예제 코드여서 오작동이나 기능이 완성되지 않은 부분이 많습니다. 단순 참고용으로만 이용바랍니다.
'개발 > C#' 카테고리의 다른 글
[C#]FOK, 최유리 매수 주문 (CYBOS PLUS/CREON PLUS) (0) | 2021.09.04 |
---|---|
[C#] 이벤트를 만들고 사용하기 (0) | 2021.01.17 |
[C#] User Control 을 툴박스에 표시하기 (0) | 2020.11.04 |
[C#] HTS 차트 흉내내기 (3) | 2020.10.15 |
[C#] 클릭(번개)주문 만들기 (CYBOS PLUS/CREON PLUS) #2 (0) | 2020.09.23 |
댓글