Files
CPRobot/CPRobotDlg.cpp
2013-08-26 14:55:27 +00:00

665 lines
32 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.
// CPRobotDlg.cpp : 구현 파일
//
#include "stdafx.h"
#include "CPRobot.h"
#include "CPRobotDlg.h"
#include <WinUser.h>
#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=(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_bPutOption(FALSE)
, m_bBuyOnBid1(FALSE)
{
m_hIcon = AfxGetApp()->LoadIcon(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; i<iCodeCnt; i++)
{
Code = (_bstr_t)pOpCode->GetData(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<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
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; i<iCodeCnt; i++)
{
m_pOpJpBid->SetInputValue(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; i<iCodeCnt; i++)
{
m_pOpJpBid->SetInputValue(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=(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());
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)
{
SwitchState(CPS_WAIT);
((CButton*)GetDlgItem(IDC_RADIO_CALLOP))->SetCheck(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);
}