[C#] 클릭(번개)주문 만들기 (CYBOS PLUS/CREON PLUS)

2020. 9. 19. 19:57개발/C#

 

요즘 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# 공부삼아 만든 예제 코드여서 오작동이나 기능이 완성되지 않은 부분이 많습니다. 단순 참고용으로만 이용바랍니다.

 

 

  • 프로필사진
    푸른목성2020.09.19 20:49

    감사합니다. 소중한 소스 잘 읽고 공부해보겠습니다. 건강하세요.~~

1 2 3 4