// CPRobotDlg.cpp : 구현 파일 // #include "stdafx.h" #include "CPRobot.h" #include "CPRobotDlg.h" #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" ICpTdUtilPtr g_pTdUtil = NULL; void StringFormat(std::string &s, const std::string fmt, ...) { std::string ss; int n, size=100; 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(IDR_MAINFRAME); m_iBalance = 0; m_pOpJpBid = NULL; m_CurCode = ""; m_fBoughtPrice = 0.0f; m_fHighestBid1 = 0.0f; m_fCurBid1 = 0.0f; m_iBoughtCnt = 0; m_iOrderNum = 0; m_enPrevState = CPS_WAIT; m_enState = CPS_WAIT; } 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_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_REFRESH_BALANCE, &CCPRobotDlg::OnBnClickedButtonRefreshBalance) ON_WM_CREATE() ON_WM_DESTROY() ON_BN_CLICKED(IDC_BUTTON_START_DEAL, &CCPRobotDlg::OnBnClickedButtonStartDeal) ON_BN_CLICKED(IDC_BUTTON_SEARCH, &CCPRobotDlg::OnBnClickedButtonSearch) ON_WM_PARENTNOTIFY() ON_WM_HOTKEY() END_MESSAGE_MAP() // CCPRobotDlg 메시지 처리기 BOOL CCPRobotDlg::OnInitDialog() { CDialog::OnInitDialog(); // 이 대화 상자의 아이콘을 설정합니다. 응용 프로그램의 주 창이 대화 상자가 아닐 경우에는 // 프레임워크가 이 작업을 자동으로 수행합니다. SetIcon(m_hIcon, TRUE); // 큰 아이콘을 설정합니다. SetIcon(m_hIcon, FALSE); // 작은 아이콘을 설정합니다. // TODO: 여기에 추가 초기화 작업을 추가합니다. return TRUE; // 포커스를 컨트롤에 설정하지 않으면 TRUE를 반환합니다. } int CCPRobotDlg::OnCreate(LPCREATESTRUCT lpCreateStruct) { if (CDialog::OnCreate(lpCreateStruct) == -1) return -1; // TODO: Add your specialized creation code here g_pTdUtil.CreateInstance(CLSID_CpTdUtil); const short iInitResult = g_pTdUtil->TradeInit(0); switch(iInitResult) { case -1: MessageBox("TradeInit 오류"); return -2; break; case 1: MessageBox("업무 키 잘못 입력됨"); return -2; break; case 2: MessageBox("계좌 비밀번호 잘못 입력됨"); return -2; break; case 3: MessageBox("취소됨"); 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(CLSID_OptionJpBid); m_EventHandler.DispEventAdvise(m_pOpJpBid); m_EventHandler.SetIEventHandler(this); ICpOptionCodePtr pOpCode; pOpCode.CreateInstance(CLSID_CpOptionCode); short iCodeCnt = pOpCode->GetCount(); string Code; for(int i=0; iGetData(0, i); m_OpCodeList.push_back(Code); } pOpCode.Release(); // 핫키 등록 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'); // 로그 폴더 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); SetForegroundWindow(); return 0; } void CCPRobotDlg::OnDestroy() { CDialog::OnDestroy(); // TODO: Add your message handler code here m_pOpJpBid.Release(); m_EventHandler.DispEventUnadvise(m_pOpJpBid); UpdateData(); SaveToFile(); m_LogFile.close(); } BOOL CCPRobotDlg::DestroyWindow() { // TODO: Add your specialized code here and/or call the base class g_pTdUtil.Release(); return CDialog::DestroyWindow(); } void CCPRobotDlg::SwitchState(const CP_STATE enState) { m_enPrevState = m_enState; m_enState = enState; } 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", m_iAmountSet); fprintf_s(fp, "매수 조건 최소 : %f", m_fMinPriceSet); fprintf_s(fp, "매수 조건 최대 : %f", m_fMaxPriceSet); fprintf_s(fp, "매도 요청 : %d", m_iPlusTick); fprintf_s(fp, "손절 범위 : %f", m_fLossCutTick); fprintf_s(fp, "트레일링 범위 : %f", m_fTrailingTick); fprintf_s(fp, "취소 시간 : %d", m_iCancelDelay); fprintf_s(fp, "풋옵션 : %d", 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", &m_iAmountSet); fscanf_s(fp, "매수 조건 최소 : %f", &m_fMinPriceSet); fscanf_s(fp, "매수 조건 최대 : %f", &m_fMaxPriceSet); fscanf_s(fp, "매도 요청 : %d", &m_iPlusTick); fscanf_s(fp, "손절 범위 : %f", &m_fLossCutTick); fscanf_s(fp, "트레일링 범위 : %f", &m_fTrailingTick); fscanf_s(fp, "취소 시간 : %d", &m_iCancelDelay); fscanf_s(fp, "풋옵션 : %d", &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 ICpTdDibPtr pTd0721 = NULL; pTd0721.CreateInstance(CLSID_CpTd0721F); pTd0721->SetInputValue(0, m_AccountNum.data()); pTd0721->SetInputValue(1, "50"); pTd0721->SetInputValue(2, "50"); pTd0721->SetInputValue(3, "10"); CString Message; do { pTd0721->BlockRequest(); m_iBalance = pTd0721->GetHeaderValue(9); Message.Format("원 (잔고 : %d원)", m_iBalance); SetDlgItemText(IDC_STATIC_BALANCE, Message.GetString()); } while(pTd0721->Continue); pTd0721.Release(); LoadFromFile(); UpdateData(FALSE); } 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(); //CPLog("Subscribe[%s]", m_OpCodeList[i].data()); if(m_pOpJpBid->GetDibStatus() != 0) { CString strErrorMsg; strErrorMsg += (LPCTSTR)m_pOpJpBid->GetDibMsg1(); strErrorMsg += (LPCTSTR)m_pOpJpBid->GetDibMsg2(); strErrorMsg.TrimRight(); AfxMessageBox(strErrorMsg); } } } catch(_com_error e) { AfxMessageBox("Subscribe Error"); } } 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) { AfxMessageBox("Unsubscribe Error"); } } void CCPRobotDlg::OnBnClickedButtonSearch() { // TODO: Add your control notification handler code here UpdateData(); m_CurCode = ""; m_fBoughtPrice = 0.0f; m_fHighestBid1 = 0.0f; m_fCurBid1 = 0.0f; m_iBoughtCnt = 0; m_iOrderNum = 0; Unsubscribe(); Subscribe(); SwitchState(CPS_LOOKING); } void CCPRobotDlg::OnBnClickedButtonStartDeal() { // TODO: Add your control notification handler code here Unsubscribe(); if(m_enState == CPS_WAIT || m_enState == CPS_LOOKING) { ((CButton*)(GetDlgItem(IDC_BUTTON_START_DEAL)))->SetCheck(TRUE); Subscribe(); SwitchState(CPS_LOOKING_DEAL); CPLog("Start Dealing"); } else { ((CButton*)(GetDlgItem(IDC_BUTTON_START_DEAL)))->SetCheck(FALSE); CPLog("Stop Dealing"); } } void CCPRobotDlg::BuyThis(const string& Code, const float fBid1Price, const int iBid1Cnt, float afAskPrice[5]) { SwitchState(CPS_BUYING); // 수량 계산 int iBuyCnt = (int)(m_iBalance / (fBid1Price*500000)); iBuyCnt = min(iBuyCnt, iBid1Cnt); // 매수 가격 const float fOrderPrice = ((m_bBuyOnBid1 == TRUE) ? fBid1Price : afAskPrice[0]); // 매수 주문 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(7, "1"); // 7- (string) 주문조건구분코드(0:없음, 1:IOC, 2:FOK) pTd6831->BlockRequest(); if(pTd6831->GetDibStatus() != 0) { CString strErrorMsg; strErrorMsg += (LPCTSTR)pTd6831->GetDibMsg1(); strErrorMsg += (LPCTSTR)pTd6831->GetDibMsg2(); strErrorMsg.TrimRight(); CPLog(strErrorMsg.GetString()); } else { CPLog("매수 요청 [%s] %f(%d)", Code.data(), afAskPrice[0], iBuyCnt); } m_CurCode = Code; m_fBoughtPrice = fOrderPrice; m_fHighestBid1 = fOrderPrice; m_fCurBid1 = fOrderPrice; m_iBoughtCnt = iBuyCnt; // *** 체결 수량 체크해야 함 m_iOrderNum = (int)pTd6831->GetHeaderValue(8); // 8 - (long) 주문번호 m_BoughtT = CTime::GetCurrentTime(); // 매도 요청 SwitchState(CPS_SELLING); int iSellAskIdx = ((m_bBuyOnBid1 == TRUE) ? (m_iPlusTick-1) : (m_iPlusTick)); iSellAskIdx = min(iSellAskIdx, 4); pTd6831->SetInputValue(4, afAskPrice[iSellAskIdx]); // 4 - (double) 주문가격 pTd6831->SetInputValue(5, "1"); // 5 - (string) 매매구분코드 (1:매도, 2:매수) pTd6831->SetInputValue(7, "0"); // 7- (string) 주문조건구분코드(0:없음, 1:IOC, 2:FOK) pTd6831->BlockRequest(); if(pTd6831->GetDibStatus() != 0) { CString strErrorMsg; strErrorMsg += (LPCTSTR)pTd6831->GetDibMsg1(); strErrorMsg += (LPCTSTR)pTd6831->GetDibMsg2(); strErrorMsg.TrimRight(); CPLog(strErrorMsg.GetString()); } else { CPLog("매도 요청 [%s] %f(%d)", Code.data(), afAskPrice[iSellAskIdx], iBuyCnt); } pTd6831.Release(); SwitchState(CPS_WAITING_SELL); } void CCPRobotDlg::CorrectToCurrent(const string& Code) { SwitchState(CPS_SELLING); // 정정 주문 ICpTdDibPtr pTd6832 = NULL; pTd6832.CreateInstance(CLSID_CpTd6831); pTd6832->SetInputValue(2, m_iOrderNum); // 2 - (long) 원주문번호 pTd6832->SetInputValue(3, m_AccountNum.data()); // 3 - (string) 계좌번호 pTd6832->SetInputValue(4, Code.data()); // 4 - (string) 종목코드 pTd6832->SetInputValue(5, m_iBoughtCnt); // 5 - (long) 주문수량 pTd6832->SetInputValue(6, m_fCurBid1); // 6 - (double)주문가격 pTd6832->SetInputValue(8, "1"); // 8 - (string) 정정 후 주문 유형 (" ":변경 안함, "1":지정가IOC, "2":시장가, "3":조건부, "4":최유리) pTd6832->SetInputValue(9, "1"); // 9 - (string) 주문조건구분코드 (" ":변경 안함, "0":없음, "1":IOC, "2":FOK) pTd6832.Release(); SwitchState(CPS_LOOKING_DEAL); CPLog("정정주문 [%s] %f(%d)", Code.data(), m_fCurBid1, m_iBoughtCnt); } void CCPRobotDlg::Received() { if(m_pOpJpBid->GetDibStatus() != 0) { CString strErrorMsg; strErrorMsg += (LPCTSTR)m_pOpJpBid->GetDibMsg1(); strErrorMsg += (LPCTSTR)m_pOpJpBid->GetDibMsg2(); strErrorMsg.TrimRight(); AfxMessageBox(strErrorMsg); return; } string Code = (_bstr_t)m_pOpJpBid->GetHeaderValue(0); const float fBid1Price = m_pOpJpBid->GetHeaderValue(19); // 매수 1 우선호가 const int iBid1Cnt = m_pOpJpBid->GetHeaderValue(24); //매수 1 우선호가잔량 float afAskPrice[5]; afAskPrice[0] = m_pOpJpBid->GetHeaderValue(2); // 2 - (float) 매도 1 우선호가 afAskPrice[1] = m_pOpJpBid->GetHeaderValue(3); // 3 - (float) 매도 2 우선호가 afAskPrice[2] = m_pOpJpBid->GetHeaderValue(4); // 4 - (float) 매도 3 우선호가 afAskPrice[3] = m_pOpJpBid->GetHeaderValue(5); // 5 - (float) 매도 4 우선호가 afAskPrice[4] = m_pOpJpBid->GetHeaderValue(6); // 6 - (float) 매도 5 우선호가 if(m_enState == CPS_WAITING_SELL) { if(Code == m_CurCode) { m_fCurBid1 = fBid1Price; if(fBid1Price > m_fHighestBid1) m_fHighestBid1 = fBid1Price; // check for trailing bid or loss cut if(m_fCurBid1 < m_fHighestBid1-m_fTrailingTick || m_fCurBid1 < m_fBoughtPrice-m_fLossCutTick) CorrectToCurrent(m_CurCode); } } const CTimeSpan ElapseT = CTime::GetCurrentTime()-m_BoughtT; if(ElapseT.GetSeconds() >= m_iCancelDelay) CorrectToCurrent(m_CurCode); try { if(m_bPutOption == FALSE && Code[0] == '2' || m_bPutOption == TRUE && Code[0] == '3') { if(fBid1Price >= m_fMinPriceSet && fBid1Price <= m_fMaxPriceSet) { CPLog("Matched [%s] %f\n", Code.data(), fBid1Price); if(m_enState == CPS_LOOKING_DEAL) { SwitchState(CPS_BUYING); Unsubscribe(); BuyThis(Code, fBid1Price, iBid1Cnt, afAskPrice); } } } } catch(_com_error e) { AfxMessageBox(e.ErrorMessage()); } } void CCPRobotDlg::CPLog(const std::string fmt, ...) { std::string ss; int n, size=100; 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) { SwitchState(CPS_WAIT); ((CButton*)GetDlgItem(IDC_RADIO_CALLOP))->SetCheck(0); ((CButton*)GetDlgItem(IDC_RADIO_PUTOP))->SetCheck(1); OnBnClickedButtonStartDeal(); } if(nHotKeyId == m_IdKeyFxStop) { if(m_enState == CPS_WAIT || m_enState == CPS_LOOKING) SwitchState(CPS_SELLING); OnBnClickedButtonStartDeal(); } __super::OnHotKey(nHotKeyId, nKey1, nKey2); }