Files
CPRobot/CPRobotDlg.cpp
2013-09-13 03:46:48 +00:00

1022 lines
56 KiB
C++
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// CPRobotDlg.cpp : 구현 파일
//
#include "stdafx.h"
#include "CPRobot.h"
#include "CPRobotDlg.h"
#include <WinUser.h>
//#include <cmath>
#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<CP_UNITINFO>::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=(n<size))==true))
ss.resize(n);
else
size *= 2;
}
s += ss;
}
CCPRobotDlg::CCPRobotDlg(CWnd* pParent /*=NULL*/)
: CDialog(CCPRobotDlg::IDD, pParent)
, m_iAmountSet(0)
, m_fMinPriceSet(0.0f)
, m_fMaxPriceSet(0.0f)
, m_iPlusTick(0)
, m_fLossCutTick(0.0f)
, m_fTrailingTick(0.0f)
, m_iCancelDelay(0)
, m_iWindUpDelay(0)
, m_iWindUpTick(0)
, m_bPutOption(FALSE)
, m_bBuyOnBid1(FALSE)
{
m_hIcon = AfxGetApp()->LoadIcon(IDI_ICON_STOCK);
m_iBalance = 0;
m_pOpJpBid = NULL;
m_bLookingDeal = FALSE;
m_pCpFConclusion = NULL;
m_bUsingConclusion = false;
}
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=(n<size))==true))
ss.resize(n);
else
size *= 2;
}
CTime time = CTime::GetCurrentTime();
string Message;
StringFormat(Message, "[%04d-%02d-%02d %02d:%02d:%02d] %s\n",
time.GetYear(),
time.GetMonth(),
time.GetDay(),
time.GetHour(),
time.GetMinute(),
time.GetSecond(),
ss.data());
TRACE(Message.data());
m_ResultList.AddString(Message.data());
if(m_ResultList.GetCurSel() == m_ResultList.GetCount()-2)
m_ResultList.SetCurSel(m_ResultList.GetCount()-1);
if(m_LogFile.is_open() == true)
{
m_LogFile << Message.data();
m_LogFile.flush();
}
}
void CCPRobotDlg::OnHotKey(UINT nHotKeyId, UINT nKey1, UINT nKey2)
{
// TODO: Add your message handler code here and/or call default
if(nHotKeyId == m_IdKeyFxCall)
{
((CButton*)GetDlgItem(IDC_RADIO_CALLOP))->SetCheck(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; i<iCodeCnt; i++)
{
ExerciseMonth = (_bstr_t)pOpCode->GetData(3, i);
if(ExerciseMonth == FirstExerciseMonth)
{
Code = (_bstr_t)pOpCode->GetData(0, i);
m_OpCodeList.push_back(Code);
m_CurPriceList.insert(map<string, CP_PRICEINFO>::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<WPARAM>(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<HCURSOR>(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; i<iCodeCnt; i++)
{
m_pOpJpBid->SetInputValue(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; i<iCodeCnt; i++)
{
m_pOpJpBid->SetInputValue(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)(m_iBalance / (fBid1Price*500000));
iBuyCnt = min(iBuyCnt, iBid1Cnt);
iBuyCnt = 10; // ***
// 매수 가격
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<CP_UNITINFO>::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<string, CP_PRICEINFO>::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_bUsingConclusion = true;
vector<CP_CONCLUSIONINFO> CopyList = m_ConclusionList;
m_bUsingConclusion = false;
for(vector<CP_CONCLUSIONINFO>::iterator iter=CopyList.begin(); iter != CopyList.end(); iter++)
{
CheckConclusion(*iter);
}
return 0;
}
void CCPRobotDlg::ReceivedDib()
{
if(m_bUsingConclusion == false)
m_ConclusionList.clear();
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_ConclusionList.push_back(Conclusion);
PostMessage(WM_PROC_CONCLUSION, 0, 0);
}