// CPRobotDlg.cpp : 구현 파일 // #include "stdafx.h" #include "CPRobot.h" #include "CPRobotDlg.h" #include //#include #ifdef _DEBUG #define new DEBUG_NEW #endif #define IDS_HOTKEY_FX_CALL "CallOpCheck" #define IDS_HOTKEY_FX_PUT "PutOpCheck" #define IDS_HOTKEY_FX_STOP "StopDealing" #define _TIMER_CHECK 100 #define _TIMER_INTERVAL 500 #define WM_PROC_PRICE (WM_USER+1) #define WM_PROC_CONCLUSION (WM_USER+2) typedef vector::iterator UnitIterator; ICpTdUtilPtr g_pTdUtil = NULL; void StringFormat(string &s, const string fmt, ...) { string ss; int n, size=512; bool b=false; va_list marker; while (!b) { ss.resize(size); va_start(marker, fmt); n = vsnprintf_s((char*)ss.c_str(), size, size, fmt.c_str(), marker); va_end(marker); if ((n>0) && ((b=(nLoadIcon(IDI_ICON_STOCK); m_iBalance = 0; m_pOpJpBid = NULL; m_bLookingDeal = FALSE; m_pCpFConclusion = NULL; } void CCPRobotDlg::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); DDX_Control(pDX, IDC_LIST_ITEMS, m_ResultList); DDX_Text(pDX, IDC_EDIT_ORDERINGPRICE, m_iAmountSet); DDX_Text(pDX, IDC_EDIT_ORDERING_TICK_MIN, m_fMinPriceSet); DDX_Text(pDX, IDC_EDIT_ORDERING_TICK_MAX, m_fMaxPriceSet); DDX_Text(pDX, IDC_EDIT_SELL_TICK, m_iPlusTick); DDX_Text(pDX, IDC_EDIT_LOSS_CUT_TICK, m_fLossCutTick); DDX_Text(pDX, IDC_EDIT_TRAING_TICK, m_fTrailingTick); DDX_Text(pDX, IDC_EDIT_CANCEL_DELAY, m_iCancelDelay); DDX_Text(pDX, IDC_EDIT_WIND_UP_DELAY, m_iWindUpDelay); DDX_CBIndex(pDX, IDC_COMBO_WINDUP_TICK, m_iWindUpTick); DDX_Radio(pDX, IDC_RADIO_CALLOP, m_bPutOption); DDX_Radio(pDX, IDC_RADIO_BID, m_bBuyOnBid1); } BEGIN_MESSAGE_MAP(CCPRobotDlg, CDialog) ON_WM_PAINT() ON_WM_QUERYDRAGICON() //}}AFX_MSG_MAP ON_BN_CLICKED(IDC_BUTTON_START_DEAL, &CCPRobotDlg::OnBnClickedButtonStartDeal) ON_BN_CLICKED(IDC_BUTTON_SEARCH, &CCPRobotDlg::OnBnClickedButtonSearch) ON_WM_PARENTNOTIFY() ON_WM_HOTKEY() ON_WM_TIMER() ON_MESSAGE(WM_PROC_PRICE, &CCPRobotDlg::OnProcPrice) ON_MESSAGE(WM_PROC_CONCLUSION, &CCPRobotDlg::OnProcConclusion) END_MESSAGE_MAP() // CCPRobotDlg 메시지 처리기 void CCPRobotDlg::CPLog(const string fmt, ...) { string ss; int n, size=1024; bool b=false; va_list marker; while (!b) { ss.resize(size); va_start(marker, fmt); n = vsnprintf_s((char*)ss.c_str(), size, size, fmt.c_str(), marker); va_end(marker); if ((n>0) && ((b=(nSetCheck(1); ((CButton*)GetDlgItem(IDC_RADIO_PUTOP))->SetCheck(0); OnBnClickedButtonStartDeal(); } if(nHotKeyId == m_IdKeyFxPut) { ((CButton*)GetDlgItem(IDC_RADIO_CALLOP))->SetCheck(0); ((CButton*)GetDlgItem(IDC_RADIO_PUTOP))->SetCheck(1); OnBnClickedButtonStartDeal(); } if(nHotKeyId == m_IdKeyFxStop) { m_bLookingDeal = FALSE; } __super::OnHotKey(nHotKeyId, nKey1, nKey2); } BOOL CCPRobotDlg::OnInitDialog() { CDialog::OnInitDialog(); // 이 대화 상자의 아이콘을 설정합니다. 응용 프로그램의 주 창이 대화 상자가 아닐 경우에는 // 프레임워크가 이 작업을 자동으로 수행합니다. SetIcon(m_hIcon, TRUE); // 큰 아이콘을 설정합니다. SetIcon(m_hIcon, FALSE); // 작은 아이콘을 설정합니다. // TODO: 여기에 추가 초기화 작업을 추가합니다. // 로그 폴더 CFileFind FileFinder; BOOL bHasFolder = FileFinder.FindFile(".\\Log\\*.*"); if(bHasFolder == FALSE) CreateDirectory(".\\Log\\", NULL); CTime time = CTime::GetCurrentTime(); string LogFileName; StringFormat(LogFileName, ".\\Log\\Log_%04d-%02d-%02d.txt", time.GetYear(), time.GetMonth(), time.GetDay()); m_LogFile.open(LogFileName.data(), std::ios_base::app | std::ios_base::out); // Trade utli 초기화 g_pTdUtil.CreateInstance(CLSID_CpTdUtil); const short iInitResult = g_pTdUtil->TradeInit(0); switch(iInitResult) { case -1: AfxMessageBox("TradeInit 오류"); return -2; break; case 1: AfxMessageBox("업무 키 잘못 입력됨"); return -2; break; case 2: AfxMessageBox("계좌 비밀번호 잘못 입력됨"); return -2; break; case 3: AfxMessageBox("취소됨"); return -2; break; } // Get Account Number _variant_t sa = g_pTdUtil->GetAccountNumber(); SAFEARRAY* pSafeArray = sa.parray; LONG iLBound; LONG iUBound; SafeArrayGetLBound(pSafeArray, 1, &iLBound); SafeArrayGetUBound(pSafeArray, 1, &iUBound); BSTR AccNum; for(LONG i=iLBound; i<=iUBound; i++) { SafeArrayGetElement(pSafeArray, &i, &AccNum); m_AccountNum = (LPCSTR)(_bstr_t)AccNum; break; } m_pOpJpBid.CreateInstance(CpSysDib::CLSID_OptionJpBid); m_EventHandlerSysDib.DispEventAdvise(m_pOpJpBid); m_EventHandlerSysDib.SetIEventHandler(this); ICpOptionCodePtr pOpCode; pOpCode.CreateInstance(CLSID_CpOptionCode); short iCodeCnt = pOpCode->GetCount(); string Code; const string FirstExerciseMonth = (_bstr_t)pOpCode->GetData(3, 0); string ExerciseMonth; CP_PRICEINFO PriceInfo = { 0.0f, }; for(int i=0; iGetData(3, i); if(ExerciseMonth == FirstExerciseMonth) { Code = (_bstr_t)pOpCode->GetData(0, i); m_OpCodeList.push_back(Code); m_CurPriceList.insert(map::value_type(Code, PriceInfo)); } } pOpCode.Release(); CPLog("최근 월물 %d개의 코드가 검색되었습니다", m_OpCodeList.size()); m_pCpFConclusion.CreateInstance(__uuidof(CpDib::CpFConclusion)); m_EventHandlerDib.DispEventAdvise(m_pCpFConclusion); m_EventHandlerDib.SetIEventHandler(this); m_pCpFConclusion->SubscribeLatest(); // 핫키 등록 m_IdKeyFxCall = GlobalAddAtom(IDS_HOTKEY_FX_CALL); RegisterHotKey(GetSafeHwnd(), m_IdKeyFxCall, MOD_CONTROL | MOD_SHIFT, 0x41+'c'-'a'); m_IdKeyFxPut = GlobalAddAtom(IDS_HOTKEY_FX_PUT); RegisterHotKey(GetSafeHwnd(), m_IdKeyFxPut, MOD_CONTROL | MOD_SHIFT, 0x41+'p'-'a'); m_IdKeyFxStop = GlobalAddAtom(IDS_HOTKEY_FX_STOP); RegisterHotKey(GetSafeHwnd(), m_IdKeyFxStop, MOD_CONTROL | MOD_SHIFT, 0x41+'x'-'a'); OnBnClickedButtonRefreshBalance(); LoadFromFile(); UpdateData(FALSE); SetTimer(_TIMER_CHECK, _TIMER_INTERVAL, NULL); SetForegroundWindow(); Subscribe(); return TRUE; // 포커스를 컨트롤에 설정하지 않으면 TRUE를 반환합니다. } BOOL CCPRobotDlg::DestroyWindow() { // TODO: Add your specialized code here and/or call the base class Unsubscribe(); m_EventHandlerSysDib.DispEventUnadvise(m_pOpJpBid); m_pOpJpBid.Release(); m_EventHandlerDib.DispEventUnadvise(m_pCpFConclusion); m_pCpFConclusion.Release(); g_pTdUtil.Release(); UpdateData(); SaveToFile(); m_LogFile.close(); return CDialog::DestroyWindow(); } void CCPRobotDlg::SaveToFile(void) { FILE* fp = NULL; const int iError = fopen_s(&fp, "setting.ini", "wt"); if(iError != 0) { AfxMessageBox("저장 실패"); return; } fprintf_s(fp, "거래 금액 : %d\n", m_iAmountSet); fprintf_s(fp, "매수 조건 최소 : %f\n", m_fMinPriceSet); fprintf_s(fp, "매수 조건 최대 : %f\n", m_fMaxPriceSet); fprintf_s(fp, "매수 취소 시간 : %d\n", m_iCancelDelay); fprintf_s(fp, "매도 요청 : %d\n", m_iPlusTick); fprintf_s(fp, "손절 범위 : %f\n", m_fLossCutTick); fprintf_s(fp, "트레일링 범위 : %f\n", m_fTrailingTick); fprintf_s(fp, "청산 시간 : %d\n", m_iWindUpDelay); fprintf_s(fp, "청산 틱 : %d\n", m_iWindUpTick); fprintf_s(fp, "1차 매수호가로 구매 : %d\n", m_bBuyOnBid1); fprintf_s(fp, "풋옵션 : %d\n", m_bPutOption); fclose(fp); fp = NULL; } void CCPRobotDlg::LoadFromFile(void) { FILE* fp = NULL; const int iError = fopen_s(&fp, "setting.ini", "rt"); if(iError != 0) return; fscanf_s(fp, "거래 금액 : %d\n", &m_iAmountSet); fscanf_s(fp, "매수 조건 최소 : %f\n", &m_fMinPriceSet); fscanf_s(fp, "매수 조건 최대 : %f\n", &m_fMaxPriceSet); fscanf_s(fp, "매수 취소 시간 : %d\n", &m_iCancelDelay); fscanf_s(fp, "매도 요청 : %d\n", &m_iPlusTick); fscanf_s(fp, "손절 범위 : %f\n", &m_fLossCutTick); fscanf_s(fp, "트레일링 범위 : %f\n", &m_fTrailingTick); fscanf_s(fp, "청산 시간 : %d\n", &m_iWindUpDelay); fscanf_s(fp, "청산 틱 : %d\n", &m_iWindUpTick); fscanf_s(fp, "1차 매수호가로 구매 : %d\n", &m_bBuyOnBid1); fscanf_s(fp, "풋옵션 : %d\n", &m_bPutOption); fclose(fp); fp = NULL; } // 대화 상자에 최소화 단추를 추가할 경우 아이콘을 그리려면 // 아래 코드가 필요합니다. 문서/뷰 모델을 사용하는 MFC 응용 프로그램의 경우에는 // 프레임워크에서 이 작업을 자동으로 수행합니다. void CCPRobotDlg::OnPaint() { if(IsIconic()) { CPaintDC dc(this); // 그리기를 위한 디바이스 컨텍스트 SendMessage(WM_ICONERASEBKGND, reinterpret_cast(dc.GetSafeHdc()), 0); // 클라이언트 사각형에서 아이콘을 가운데에 맞춥니다. int cxIcon = GetSystemMetrics(SM_CXICON); int cyIcon = GetSystemMetrics(SM_CYICON); CRect rect; GetClientRect(&rect); int x = (rect.Width() - cxIcon + 1) / 2; int y = (rect.Height() - cyIcon + 1) / 2; // 아이콘을 그립니다. dc.DrawIcon(x, y, m_hIcon); } else { CDialog::OnPaint(); } } // 사용자가 최소화된 창을 끄는 동안에 커서가 표시되도록 시스템에서 이 함수를 호출합니다. HCURSOR CCPRobotDlg::OnQueryDragIcon() { return static_cast(m_hIcon); } void CCPRobotDlg::OnBnClickedButtonRefreshBalance() { // TODO: Add your control notification handler code here try { ICpTdDibPtr pTd0721 = NULL; pTd0721.CreateInstance(CLSID_CpTd0721F); pTd0721->SetInputValue(0, m_AccountNum.data()); // 0 - (string) 계좌번호 pTd0721->SetInputValue(1, "50"); // 1 - (string) 상품관리 구분[defaut:50] pTd0721->SetInputValue(2, ""); // 2 – (string) 종목코드[default:""] pTd0721->SetInputValue(3, "10"); // 3 – (long) 요청건수[default:10] - 최대 20개 string Message; do { pTd0721->BlockRequest(); m_iBalance = pTd0721->GetHeaderValue(9); StringFormat(Message, "원 (잔고 : %d원)", m_iBalance); SetDlgItemText(IDC_STATIC_BALANCE, Message.data()); } while(pTd0721->Continue); pTd0721.Release(); } catch(_com_error e) { string Message = "[잔고 조회 실패]\n"; Message += e.ErrorMessage(); AfxMessageBox(Message.data()); } } void CCPRobotDlg::Subscribe(void) { const int iCodeCnt = m_OpCodeList.size(); try { CPLog("Subscribe"); for(int i=0; iSetInputValue(0, m_OpCodeList[i].data()); m_pOpJpBid->SubscribeLatest(); if(m_pOpJpBid->GetDibStatus() != 0) { string strErrorMsg; strErrorMsg += (LPCTSTR)m_pOpJpBid->GetDibMsg1(); strErrorMsg += (LPCTSTR)m_pOpJpBid->GetDibMsg2(); CPLog(strErrorMsg.data()); } } } catch(_com_error e) { string Message = "[Subscribe Error]\n"; Message += e.ErrorMessage(); CPLog(Message.data()); } } void CCPRobotDlg::Unsubscribe(void) { const int iCodeCnt = m_OpCodeList.size(); try { CPLog("Unsubscribe"); for(int i=0; iSetInputValue(0, m_OpCodeList[i].data()); m_pOpJpBid->Unsubscribe(); } } catch(_com_error e) { string Message = "[Unsubscribe Error]\n"; Message += e.ErrorMessage(); CPLog(Message.data()); } } void CCPRobotDlg::OnBnClickedButtonSearch() { // TODO: Add your control notification handler code here UpdateData(); SaveToFile(); Unsubscribe(); Subscribe(); } void CCPRobotDlg::OnBnClickedButtonStartDeal() { // TODO: Add your control notification handler code here //Unsubscribe(); UpdateData(); m_bLookingDeal = TRUE; CPLog("Start Dealing"); m_DealStartT = CTime::GetCurrentTime(); //Subscribe(); } void CCPRobotDlg::BuyThis(const string& Code, const float fBid1Price, const int iBid1Cnt, float afAskPrice[5]) { // 수량 계산 int iBuyCnt = (int)(min(m_iAmountSet, m_iBalance) / (fBid1Price*500000)); iBuyCnt = min(iBuyCnt, iBid1Cnt); #ifdef DEBUG iBuyCnt = 10; // *** #endif // 매수 가격 const float fOrderPrice = ((m_bBuyOnBid1 == TRUE) ? fBid1Price : afAskPrice[0]); // 매수 주문 try { ICpTdDibPtr pTd6831 = NULL; pTd6831.CreateInstance(CLSID_CpTd6831); pTd6831->SetInputValue(1, m_AccountNum.data()); // 1 - (string) 계좌번호 pTd6831->SetInputValue(2, Code.data()); // 2 - (string) 종목코드 pTd6831->SetInputValue(3, iBuyCnt); // 3 - (long) 주문수량 pTd6831->SetInputValue(4, fOrderPrice); // 4 - (double) 주문가격 pTd6831->SetInputValue(5, "2"); // 5 - (string) 매매구분코드 (1:매도, 2:매수) pTd6831->SetInputValue(6, "1"); // 6 - (string) 주문유형코드 (1:지정가[default] 2:시장가 3:조건부지정가 4:최유리지정가) pTd6831->SetInputValue(7, "0"); // 7- (string) 주문조건구분코드(0:없음, 1:IOC, 2:FOK) CPLog("[매수 요청 중] %s(%d) : %3.2f", Code.data(), iBuyCnt, afAskPrice[0]); pTd6831->BlockRequest(); if(pTd6831->GetDibStatus() != 0) { string strErrorMsg; strErrorMsg += (LPCTSTR)pTd6831->GetDibMsg1(); strErrorMsg += (LPCTSTR)pTd6831->GetDibMsg2(); CPLog(strErrorMsg.data()); } else { CP_UNITINFO Unit; Unit.m_Code = Code; Unit.m_fBoughtPrice = fOrderPrice; Unit.m_fHighestPrice = fOrderPrice; Unit.m_iCnt = iBuyCnt; Unit.m_iOrderNum = (int)pTd6831->GetHeaderValue(8); // 8 - (long) 주문번호 Unit.m_Time = CTime::GetCurrentTime(); m_BidOrderList.push_back(Unit); } CPLog("[매수 요청 끝] %s(%d) : %3.2f", Code.data(), iBuyCnt, afAskPrice[0]); pTd6831.Release(); } catch(_com_error e) { string Message = "[매수 요청 에러]\n"; Message += e.ErrorMessage(); CPLog(Message.data()); } } void CCPRobotDlg::SellThis(CP_UNITINFO& AskInfo) { // 매도 요청 try { ICpTdDibPtr pTd6831 = NULL; pTd6831.CreateInstance(CLSID_CpTd6831); pTd6831->SetInputValue(1, m_AccountNum.data()); // 1 - (string) 계좌번호 pTd6831->SetInputValue(2, AskInfo.m_Code.data()); // 2 - (string) 종목코드 pTd6831->SetInputValue(3, AskInfo.m_iCnt); // 3 - (long) 주문수량 const float fAskPrice = AskInfo.m_fBoughtPrice + m_iPlusTick*0.01f; pTd6831->SetInputValue(4, fAskPrice); // 4 - (double) 주문가격 pTd6831->SetInputValue(5, "1"); // 5 - (string) 매매구분코드 (1:매도, 2:매수) pTd6831->SetInputValue(6, "1"); // 6 - (string) 주문유형코드 (1:지정가[default] 2:시장가 3:조건부지정가 4:최유리지정가) pTd6831->SetInputValue(7, "0"); // 7- (string) 주문조건구분코드(0:없음, 1:IOC, 2:FOK) CPLog("[매도 요청 중] %s(%d) : %3.2f", AskInfo.m_Code.data(), AskInfo.m_iCnt, fAskPrice); pTd6831->BlockRequest(); if(pTd6831->GetDibStatus() != 0) { string strErrorMsg; strErrorMsg += (LPCTSTR)pTd6831->GetDibMsg1(); strErrorMsg += (LPCTSTR)pTd6831->GetDibMsg2(); CPLog(strErrorMsg.data()); } else { AskInfo.m_iOrderNum = pTd6831->GetHeaderValue(8); // 8 - (long) 주문번호 m_AskOrderList.push_back(AskInfo); } CPLog("[매도 요청 끝] %s(%d) : %3.2f", AskInfo.m_Code.data(), AskInfo.m_iCnt, fAskPrice); pTd6831.Release(); } catch(_com_error e) { string Message = "[매도 요청 에러]\n"; Message += e.ErrorMessage(); CPLog(Message.data()); } } void CCPRobotDlg::WindUp(const CP_UNITINFO& Unit) { // 정정 주문 for(UnitIterator iter = m_AskOrderList.begin(); iter != m_AskOrderList.end(); iter++) { if(iter->m_Code == Unit.m_Code && iter->m_iOrderNum == Unit.m_iOrderNum) { try { ICpTdDibPtr pTd6832 = NULL; pTd6832.CreateInstance(CLSID_CpTd6832); pTd6832->SetInputValue(2, iter->m_iOrderNum); // 2 - (long) 원주문번호 pTd6832->SetInputValue(3, m_AccountNum.data()); // 3 - (string) 계좌번호 pTd6832->SetInputValue(4, Unit.m_Code.data()); // 4 - (string) 종목코드 pTd6832->SetInputValue(5, iter->m_iCnt); // 5 - (long) 주문수량 //const double dPrice = (double)m_CurPriceList[Code].m_afBidPrice[m_iWindUpTick]; const double dPrice = 0.01; // *** pTd6832->SetInputValue(6, dPrice); // 6 - (double)주문가격 pTd6832->SetInputValue(8, " "); // 8 - (string) 정정 후 주문 유형 (" ":변경 안함, "1":지정가IOC, "2":시장가, "3":조건부, "4":최유리) pTd6832->SetInputValue(9, " "); // 9 - (string) 주문조건구분코드 (" ":변경 안함, "0":없음, "1":IOC, "2":FOK) pTd6832->SetInputValue(10, "50"); // 10- 상품관리구분코드[Default::50] CPLog("[정정 요청 중] %s(%d) : %3.2f 주문번호 : %d 원주문번호 : %d", Unit.m_Code.data(), Unit.m_iCnt, dPrice, (int)iter->m_iOrderNum, (int)iter->m_iOrderNum); pTd6832->BlockRequest(); if(pTd6832->GetDibStatus() != 0) { string strErrorMsg; strErrorMsg += (LPCTSTR)pTd6832->GetDibMsg1(); strErrorMsg += (LPCTSTR)pTd6832->GetDibMsg2(); CPLog(strErrorMsg.data()); } else { m_AskOrderList.erase(iter); } CPLog("[정정 요청 끝] %s(%d) : %3.2f 주문번호 : %d 원주문번호 : %d", Unit.m_Code.data(), Unit.m_iCnt, dPrice, (int)pTd6832->GetHeaderValue(6), (int)pTd6832->GetHeaderValue(1)); pTd6832.Release(); } catch(_com_error e) { string Message = "[정정 주문 에러]\n"; Message += e.ErrorMessage(); CPLog(Message.data()); } break; } } } void CCPRobotDlg::CancelOrder(const CP_UNITINFO& Unit) { const int iCnt = m_BidOrderList.size(); vector::iterator iter = m_BidOrderList.begin(); while(iter != m_BidOrderList.end()) { if(iter->m_Code == Unit.m_Code && iter->m_iOrderNum == Unit.m_iOrderNum) { try { ICpTdDibPtr pTd6833 = NULL; pTd6833.CreateInstance(CLSID_CpTd6833); pTd6833->SetInputValue(2, iter->m_iOrderNum); // 2 - (long) 원주문번호 pTd6833->SetInputValue(3, m_AccountNum.data()); // 3 - (string) 계좌번호 pTd6833->SetInputValue(4, iter->m_Code.data()); // 4 - (string) 종목코드 pTd6833->SetInputValue(5, iter->m_iCnt); // 5 - (long) 취소 수량 (주) 정확한 취소수량을 입력해야함 pTd6833->SetInputValue(6, 50); // 6 - 상품관리구분코드[Default::50] 계좌구분 CPLog("[취소 요청 중] %s(%d) : 시장가 ", Unit.m_Code.data(), Unit.m_iCnt); pTd6833->BlockRequest(); if(pTd6833->GetDibStatus() != 0) { string strErrorMsg; strErrorMsg += (LPCTSTR)pTd6833->GetDibMsg1(); strErrorMsg += (LPCTSTR)pTd6833->GetDibMsg2(); CPLog(strErrorMsg.data()); } // 취소 요청 중에 체결될 수 있기 때문에 리스트에서 그냥 삭제 m_BidOrderList.erase(iter); CPLog("[취소 요청 끝] %s(%d) : 시장가 ", Unit.m_Code.data(), Unit.m_iCnt); pTd6833.Release(); } catch(_com_error e) { string Message = "[취소 주문 에러]\n"; Message += e.ErrorMessage(); CPLog(Message.data()); } break; } iter++; } } void CCPRobotDlg::OnTimer(UINT_PTR nIDEvent) { // TODO: Add your message handler code here and/or call default CTime CurTime = CTime::GetCurrentTime(); CTimeSpan ElapseTime; // 주문 취소 for(UnitIterator UnitIter=m_BidOrderList.begin(); UnitIter != m_BidOrderList.end(); UnitIter++) { ElapseTime = CurTime-UnitIter->m_Time; if(ElapseTime.GetSeconds()*1000 >= m_iCancelDelay) { CancelOrder(*UnitIter); UnitIter = m_BidOrderList.begin(); } if(m_BidOrderList.empty() == true) break; } // 청산 for(UnitIterator UnitIter=m_AskOrderList.begin(); UnitIter != m_AskOrderList.end(); UnitIter++) { ElapseTime = CurTime-UnitIter->m_Time; if(ElapseTime.GetSeconds()*1000 >= m_iWindUpDelay) { CPLog("[청산 요청] %s(%d)", UnitIter->m_Code.data(), UnitIter->m_iCnt); WindUp(*UnitIter); UnitIter = m_AskOrderList.begin(); } if(m_AskOrderList.empty() == true) break; } // 물량 찾기 취소 if(m_bLookingDeal == TRUE) { ElapseTime = CurTime - m_DealStartT; if(ElapseTime.GetSeconds()*1000 >= m_iCancelDelay) { CPLog("Cancel Dealing"); m_bLookingDeal = FALSE; } } __super::OnTimer(nIDEvent); } void CCPRobotDlg::CheckPrice(const string Code) { const float fBid1Price = m_CurPriceList[Code].m_afBidPrice[0]; const int iBid1Cnt = m_CurPriceList[Code].m_aiBidCnt[0]; for(UnitIterator iter = m_BidOrderList.begin(); iter != m_BidOrderList.end(); iter++) { if(iter->m_Code == Code) { // 최고가 갱신 if(iter->m_fHighestPrice < fBid1Price) iter->m_fHighestPrice = fBid1Price; } } int iAskSize = m_AskOrderList.size(); for(UnitIterator iter = m_AskOrderList.begin(); iter != m_AskOrderList.end(); iter++) { if(iter->m_Code == Code) { // 최고가 갱신 if(fBid1Price > iter->m_fHighestPrice) iter->m_fHighestPrice = fBid1Price; // 트레일링 or 손절 if(fBid1Price <= iter->m_fHighestPrice-m_fTrailingTick) { CPLog("[트레일링 매도 요청] %s(%d) : 고점(%3.2f) 현재가(%3.2f)", iter->m_Code.data(), iter->m_iCnt, iter->m_fHighestPrice, fBid1Price); WindUp(*iter); iter = m_AskOrderList.begin(); } else if(fBid1Price <= iter->m_fBoughtPrice-m_fLossCutTick) { CPLog("[손절 매도 요청] %s(%d) 구매가(%3.2f) 현재가(%3.2f)", iter->m_Code.data(), iter->m_iCnt, iter->m_fBoughtPrice, fBid1Price); WindUp(*iter); iter = m_AskOrderList.begin(); } } if(m_AskOrderList.empty() == true) break; } if(m_bPutOption == FALSE && Code[0] == '2' || m_bPutOption == TRUE && Code[0] == '3') { if(fBid1Price >= m_fMinPriceSet && fBid1Price <= m_fMaxPriceSet) { if(m_bLookingDeal == TRUE) { CPLog("Matched [%s] %3.2f", Code.data(), fBid1Price); m_bLookingDeal = FALSE; BuyThis(Code, fBid1Price, iBid1Cnt, m_CurPriceList[Code].m_afAskPrice); } } } } LRESULT CCPRobotDlg::OnProcPrice(WPARAM wParam, LPARAM lParam) { for(map::iterator iter = m_CurPriceList.begin(); iter != m_CurPriceList.end(); iter++) { if(iter->second.m_bUpdated == true) { CheckPrice(iter->first); iter->second.m_bUpdated = false; } } return 0; } void CCPRobotDlg::ReceivedSysDib() { const string Code = (_bstr_t)m_pOpJpBid->GetHeaderValue(0); CP_PRICEINFO PriceInfo; PriceInfo.m_afAskPrice[0] = m_pOpJpBid->GetHeaderValue(2); // 2 - (float) 매도 1 우선호가 PriceInfo.m_afAskPrice[1] = m_pOpJpBid->GetHeaderValue(3); // 3 - (float) 매도 2 우선호가 PriceInfo.m_afAskPrice[2] = m_pOpJpBid->GetHeaderValue(4); // 4 - (float) 매도 3 우선호가 PriceInfo.m_afAskPrice[3] = m_pOpJpBid->GetHeaderValue(5); // 5 - (float) 매도 4 우선호가 PriceInfo.m_afAskPrice[4] = m_pOpJpBid->GetHeaderValue(6); // 6 - (float) 매도 5 우선호가 PriceInfo.m_aiAskCnt[0] = m_pOpJpBid->GetHeaderValue(7); // 7 - (long) 매도 1 우선호가잔량 PriceInfo.m_aiAskCnt[1] = m_pOpJpBid->GetHeaderValue(8); // 8 - (long) 매도 2 우선호가잔량 PriceInfo.m_aiAskCnt[2] = m_pOpJpBid->GetHeaderValue(9); // 9 - (long) 매도 3 우선호가잔량 PriceInfo.m_aiAskCnt[3] = m_pOpJpBid->GetHeaderValue(10); // 10 - (long) 매도 4 우선호가잔량 PriceInfo.m_aiAskCnt[4] = m_pOpJpBid->GetHeaderValue(11); // 11 - (long) 매도 5 우선호가잔량 PriceInfo.m_afBidPrice[0] = m_pOpJpBid->GetHeaderValue(19); // 19 - (float) 매수 1 우선호가 PriceInfo.m_afBidPrice[1] = m_pOpJpBid->GetHeaderValue(20); // 20 - (float) 매수 2 우선호가 PriceInfo.m_afBidPrice[2] = m_pOpJpBid->GetHeaderValue(21); // 21 - (float) 매수 3 우선호가 PriceInfo.m_afBidPrice[3] = m_pOpJpBid->GetHeaderValue(22); // 22 - (float) 매수 4 우선호가 PriceInfo.m_afBidPrice[4] = m_pOpJpBid->GetHeaderValue(23); // 23 - (float) 매수 5 우선호가 PriceInfo.m_aiBidCnt[0] = m_pOpJpBid->GetHeaderValue(24); // 24 - (long) 매수 1 우선호가잔량 PriceInfo.m_aiBidCnt[1] = m_pOpJpBid->GetHeaderValue(25); // 25 - (long) 매수 2 우선호가잔량 PriceInfo.m_aiBidCnt[2] = m_pOpJpBid->GetHeaderValue(26); // 26 - (long) 매수 3 우선호가잔량 PriceInfo.m_aiBidCnt[3] = m_pOpJpBid->GetHeaderValue(27); // 27 - (long) 매수 4 우선호가잔량 PriceInfo.m_aiBidCnt[4] = m_pOpJpBid->GetHeaderValue(28); // 28 - (long) 매수 5 우선호가잔량 PriceInfo.m_bUpdated = true; m_CurPriceList[Code] = PriceInfo; PostMessage(WM_PROC_PRICE, (WPARAM)&Code, 0); } void CCPRobotDlg::CheckConclusion(const CP_CONCLUSIONINFO& ConclusionInfo) { const string Code = ConclusionInfo.m_Code; const int iConclusionCnt = ConclusionInfo.m_iCnt; const double ConclusionPrice = ConclusionInfo.m_dPrice; const int iOrderNum = ConclusionInfo.m_iOrderNum; const int iOrgOrderNum = ConclusionInfo.m_iOrgOrderNum; const string astrType[] = { "", "매도", "매수" }; const int iOrderType = ConclusionInfo.m_enOrderType; const string astrResult[] = { "", "접수", "정정확인", "취소확인", "체결", "거부" }; const int iOrderState = ConclusionInfo.m_enState; CPLog("[%s 결과][%s] %s(%d) : %3.2f 주문번호:%d 원주문번호:%d", astrType[iOrderType].data(), astrResult[iOrderState].data(), Code.data(), iConclusionCnt, ConclusionPrice, iOrderNum, iOrgOrderNum); CP_UNITINFO AskData; if(ConclusionInfo.m_enState == CPOS_CONCLUTION) { if(ConclusionInfo.m_enOrderType == CPOT_BID) { BOOL bCheck = FALSE; for(UnitIterator UnitIter = m_BidOrderList.begin(); UnitIter != m_BidOrderList.end(); UnitIter++) { if(UnitIter->m_Code == Code && UnitIter->m_iOrderNum == iOrderNum) { if(iConclusionCnt == UnitIter->m_iCnt) { AskData = *UnitIter; AskData.m_iOrderNum = iOrderNum; AskData.m_fBoughtPrice = (float)ConclusionPrice; AskData.m_fHighestPrice = (float)ConclusionPrice; m_BidOrderList.erase(UnitIter); bCheck = TRUE; } else if(iConclusionCnt < UnitIter->m_iCnt) { AskData = *UnitIter; AskData.m_iOrderNum = iOrderNum; AskData.m_iCnt = iConclusionCnt; AskData.m_fBoughtPrice = (float)ConclusionPrice; AskData.m_fHighestPrice = (float)ConclusionPrice; UnitIter->m_iCnt = UnitIter->m_iCnt-iConclusionCnt; bCheck = TRUE; } break; } } // 매수 취소를 했지만 매수 체결이 먼저 된 경우임 // 청산 타이밍이 늦어진다는 문제가 있을 수 있음. if(bCheck == FALSE) { AskData.m_Code = ConclusionInfo.m_Code; AskData.m_iCnt = ConclusionInfo.m_iCnt; AskData.m_fBoughtPrice = (float)ConclusionPrice; AskData.m_fHighestPrice = (float)ConclusionPrice; AskData.m_Time = CTime::GetCurrentTime(); AskData.m_iOrderNum = ConclusionInfo.m_iOrderNum; } SellThis(AskData); } else if(ConclusionInfo.m_enOrderType == CPOT_ASK) { for(UnitIterator UnitIter = m_AskOrderList.begin(); UnitIter != m_AskOrderList.end(); UnitIter++) { if(UnitIter->m_Code == Code && UnitIter->m_iOrderNum == iOrderNum) { if(iConclusionCnt == UnitIter->m_iCnt) m_AskOrderList.erase(UnitIter); else if(iConclusionCnt < UnitIter->m_iCnt) UnitIter->m_iCnt = UnitIter->m_iCnt-iConclusionCnt; break; } } if(m_AskOrderList.empty() == true) { OnBnClickedButtonRefreshBalance(); SaveToFile(); } } } } LRESULT CCPRobotDlg::OnProcConclusion(WPARAM wParam, LPARAM lParam) { m_CS.Lock(); vector CopyList = m_ConclusionList; m_CS.Unlock(); for(vector::iterator iter=CopyList.begin(); iter != CopyList.end(); iter++) { CheckConclusion(*iter); } return 0; } void CCPRobotDlg::ReceivedDib() { CP_CONCLUSIONINFO Conclusion; Conclusion.m_Code = (LPCSTR)(_bstr_t)m_pCpFConclusion->GetHeaderValue(9); // 9 - (string) 종목코드 Conclusion.m_iOrderNum = m_pCpFConclusion->GetHeaderValue(5); // 5 - (long) 주문번호 Conclusion.m_iOrgOrderNum = m_pCpFConclusion->GetHeaderValue(6); // 6 - (long) 원주문번호 Conclusion.m_dPrice = m_pCpFConclusion->GetHeaderValue(4); // 4 - (double) 체결가격 Conclusion.m_iCnt = m_pCpFConclusion->GetHeaderValue(3); // 3 - (long) 체결수량 const string OrderType = (LPCSTR)(_bstr_t)m_pCpFConclusion->GetHeaderValue(12); // 12 - (string) 매매구분 코드(1:매도, 2:매수) const string OrderState = (LPCSTR)(_bstr_t)m_pCpFConclusion->GetHeaderValue(44); // 44 - (string) 주문상태구분코드 (1:접수 2:정정확인 3:취소확인 4:체결 5:거부) Conclusion.m_enState = (CP_ORDER_STATE)atoi(OrderState.data()); Conclusion.m_enOrderType = (CP_ORDER_TYPE)atoi(OrderType.data()); m_CS.Lock(); m_ConclusionList.clear(); m_ConclusionList.push_back(Conclusion); m_CS.Unlock(); PostMessage(WM_PROC_CONCLUSION, 0, 0); }