| | |
| | | #include <wx/panel.h> |
| | | #include <wx/sizer.h> |
| | | #include <string.h> |
| | | #include "MyNetworkApi.h" |
| | | #include <thread> |
| | | #include "DataParseUtil.h" |
| | | #include "../common_nopch/StringUtil.h" |
| | | #include "../common_nopch/TimeUtil.h" |
| | | #include "MyConfigUtil.h" |
| | | #include "TickFrame.h" |
| | | #include <wx/app.h> |
| | | #include "../common_nopch/Win32Util.h" |
| | | |
| | | |
| | | #define MSG_SHOW_TIME 5 * 1000 |
| | | |
| | | #define COLOR_VALID wxColor(0,0,0) |
| | | #define COLOR_INVALID wxColor(164,164,164) |
| | | |
| | | |
| | | BEGIN_EVENT_TABLE(MainFrame, wxFrame) |
| | | EVT_MENU(wxID_ABOUT, MainFrame::OnAbout) |
| | | EVT_MENU(wxID_EXIT, MainFrame::OnQuit) |
| | | EVT_TEXT_ENTER(wxID_ANY, MainFrame::OnTextEnter) |
| | | END_EVENT_TABLE() |
| | | |
| | | MainFrame::MainFrame(const wxString& title):wxFrame(NULL, wxID_ANY, title, wxDefaultPosition, wxSize(MAIN_WINDOW_WIDTH, MAIN_WINDOW_HEIGHT)) { |
| | | MainFrame::MainFrame(const wxString& title, wxPoint position, wxSize size) :wxFrame(NULL, wxID_ANY, title, position, size) { |
| | | |
| | | wxIcon icon; |
| | | icon.LoadFile("logo.ico", wxBITMAP_TYPE_ICO); // 替换 "app_icon.ico" 为你的应用程序图标文件路径 |
| | | SetIcon(icon); |
| | | //SetTransparent(225); |
| | | |
| | | |
| | | |
| | | viewManager = new ViewManager(); |
| | | viewManager->initView(this); |
| | | |
| | | initData(); |
| | | bindEvent(); |
| | | initTask(); |
| | | Bind(wxEVT_SHOW, [this](wxShowEvent& event) { |
| | | this->SetWindowStyleFlag(GetWindowStyleFlag() | wxSTAY_ON_TOP); |
| | | }); |
| | | this->SetWindowStyleFlag(GetWindowStyleFlag() | wxSTAY_ON_TOP); |
| | | } |
| | | |
| | | |
| | |
| | | |
| | | void MainFrame::OnAbout(wxCommandEvent& event) { |
| | | |
| | | } |
| | | } |
| | | |
| | | void MainFrame::OnTextEnter(wxCommandEvent& event) |
| | | { |
| | | |
| | | wxTextCtrl* textCtrl = dynamic_cast<wxTextCtrl*>(event.GetEventObject()); |
| | | string value = textCtrl->GetValue().ToStdString(); |
| | | if (textCtrl == viewManager->sellWidgets->buyMoney) { |
| | | |
| | | if (!viewManager->sellWidgets->buyLock->GetValue()) { |
| | | return; |
| | | } |
| | | |
| | | if (!StringUtil::isNumber(value)) { |
| | | wxMessageBox("输入格式错误"); |
| | | return; |
| | | } |
| | | MyConfigUtil::setBuyMoney(stoi(value.c_str())); |
| | | wxMessageBox("锁定买入金额成功"); |
| | | } |
| | | else if (textCtrl == viewManager->sellWidgets->sellMoney) { |
| | | if (!viewManager->sellWidgets->sellLock->GetValue()) { |
| | | return; |
| | | } |
| | | if (!StringUtil::isNumber(value)) { |
| | | wxMessageBox("输入格式错误"); |
| | | return; |
| | | } |
| | | MyConfigUtil::setSellMoney(stoi(value.c_str())); |
| | | wxMessageBox("锁定卖出金额成功"); |
| | | } |
| | | |
| | | |
| | | } |
| | | |
| | | void MainFrame::bindEvent() |
| | | { |
| | | Bind(wxEVT_CLOSE_WINDOW, &MainFrame::OnClose, this); |
| | | |
| | | viewManager->topWidgets->refreshBtn->Bind(wxEVT_BUTTON, &MainFrame::OnBtnRefreshClick, this); |
| | | viewManager->sellWidgets->buyBtn->Bind(wxEVT_BUTTON, &MainFrame::OnBtnBuyClick, this); |
| | | viewManager->sellWidgets->sellBtn->Bind(wxEVT_BUTTON, &MainFrame::OnBtnSellClick, this); |
| | | viewManager->positionWidgets->listCtrlReport->Bind(wxEVT_DATAVIEW_SELECTION_CHANGED, &MainFrame::OnPositionSelectionChanged, this); |
| | | viewManager->topWidgets->btnBackTest->Bind(wxEVT_BUTTON, &MainFrame::OnBtnBackTest, this); |
| | | for (std::list<wxButton*>::iterator e = viewManager->sellWidgets->sellNums.begin(); e != viewManager->sellWidgets->sellNums.end(); ++e) { |
| | | wxButton* sellBtn = *e; |
| | | //sellBtn->Bind(wxEVT_BUTTON, &MainFrame::OnBtnSellNum, this); |
| | | sellBtn->Bind(wxEVT_BUTTON, [this](wxCommandEvent& event) { |
| | | wxButton* btn = (wxButton*)event.GetEventObject(); |
| | | this->viewManager->sellWidgets->sellMoney->SetLabelText(btn->GetLabelText()); |
| | | }); |
| | | } |
| | | |
| | | |
| | | } |
| | | |
| | | void MainFrame::initData() |
| | | { |
| | | // -----------------------初始化掘金参数-------------------------- |
| | | JueJinParams jueJinParams = MyConfigUtil::getJueJinParams(); |
| | | tickDataRequestStrategy = new TickDataRequestStrategy(jueJinParams.token, jueJinParams.strategy_id, MODE_LIVE, this, &MainFrame::tickDataCallback); |
| | | // 设置回测参数 |
| | | tickDataRequestStrategy->set_token(jueJinParams.token.c_str()); |
| | | tickDataRequestStrategy->set_strategy_id(jueJinParams.strategy_id.c_str()); |
| | | tickDataRequestStrategy->set_mode(MODE_LIVE); |
| | | JueJinDataUtil::init(jueJinParams.token); |
| | | MyNetworkApi::set_server_info("43.138.167.68", 13008, "43.138.167.68", 13008); |
| | | |
| | | |
| | | // -----------------------初始化快捷键-------------------------- |
| | | wxAcceleratorEntry entries[2] = { |
| | | wxAcceleratorEntry(wxACCEL_SHIFT, WXK_F10, 901), |
| | | wxAcceleratorEntry(wxACCEL_CTRL, 'H', 902) |
| | | }; |
| | | |
| | | auto acceleratorTable = wxAcceleratorTable(2, entries); |
| | | this->SetAcceleratorTable(acceleratorTable); |
| | | this->Bind(wxEVT_MENU, [this](wxCommandEvent& event) { |
| | | this->OnBtnSellClick(event); |
| | | }, 901); |
| | | this->Bind(wxEVT_MENU, [this](wxCommandEvent& event) { |
| | | for (std::list<PositionInfo>::iterator e = this->positionList.begin(); e != this->positionList.end(); e++) { |
| | | PositionInfo info = *e; |
| | | if (this->selectPositionId == info.id) { |
| | | try { |
| | | Sleep(200); |
| | | CallAfter([info]() { |
| | | thread t(Win32Util::addToTHS, info.underlyingMarketInfo.code.ToStdString()); |
| | | t.detach(); |
| | | }); |
| | | |
| | | } |
| | | catch (...) { |
| | | |
| | | } |
| | | break; |
| | | } |
| | | } |
| | | |
| | | }, 902); |
| | | |
| | | |
| | | // -----------------------卖出参数初始化-------------------------- |
| | | int buyMoney = MyConfigUtil::getBuyMoney(); |
| | | int sellMoney = MyConfigUtil::getSellMoney(); |
| | | viewManager->sellWidgets->buyMoney->SetValue(to_string(buyMoney)); |
| | | viewManager->sellWidgets->sellMoney->SetValue(to_string(sellMoney)); |
| | | viewManager->sellWidgets->buyLock->SetValue(TRUE); |
| | | viewManager->sellWidgets->sellLock->SetValue(TRUE); |
| | | killed = FALSE; |
| | | blinkingMessageDialog = nullptr; |
| | | } |
| | | |
| | | void MainFrame::initTask() |
| | | { |
| | | thread t(MainFrame::startRequestPositionsTask, this); |
| | | t.detach(); |
| | | |
| | | thread t2(MainFrame::startRequestMoneyTask, this); |
| | | t2.detach(); |
| | | |
| | | |
| | | thread t1(MainFrame::runJueJinStrategy, this); |
| | | t1.detach(); |
| | | } |
| | | |
| | | void MainFrame::requestPositions() |
| | | { |
| | | |
| | | cout << "###########请求持仓##########" << endl; |
| | | string result = MyNetworkApi::get_all_positions(); |
| | | if (this == nullptr) { |
| | | return; |
| | | } |
| | | requestCount += 1; |
| | | |
| | | std::list < PositionInfo> plist = DataParseUtil::parsePositionList(result); |
| | | //根据持仓排序, |
| | | plist.sort([](PositionInfo p1, PositionInfo p2) { |
| | | return p1.availablePosition == p2.availablePosition? p1.createTime > p2.createTime: p1.availablePosition > p2.availablePosition; |
| | | }); |
| | | |
| | | |
| | | |
| | | |
| | | if (requestCount>1&&this->orginPositionList.size() != plist.size()) { |
| | | CallAfter([this]() { |
| | | this->blinkingMessageDialog = new BlinkingMessageDialog(this, "可转债有新下单"); |
| | | this->blinkingMessageDialog->show(); |
| | | }); |
| | | } |
| | | this->orginPositionList = plist; |
| | | |
| | | |
| | | viewManager->positionWidgets->listCtrlReport->DeleteAllItems(); |
| | | |
| | | // 按条件过滤 |
| | | std::list < PositionInfo> temList; |
| | | for (std::list<PositionInfo>::iterator e = plist.begin(); e != plist.end(); ++e) { |
| | | PositionInfo p = *e; |
| | | if (!viewManager->sellWidgets->showAllPosition->GetValue()) { |
| | | if (p.availablePosition > 0) { |
| | | temList.push_back(*e); |
| | | } |
| | | } |
| | | else { |
| | | temList.push_back(*e); |
| | | } |
| | | |
| | | } |
| | | this->positionList = temList; |
| | | |
| | | int index = 0; |
| | | for (std::list<PositionInfo>::iterator e = positionList.begin(); e != positionList.end(); ++e) { |
| | | PositionInfo p = *e; |
| | | //{ "名称", "涨幅", "现价", "L1现手", "剩余持仓", "持仓金额", "盈亏", "盈亏比", "正股名称", "更多" }; |
| | | wxVector<wxVariant> data; |
| | | bool hasPosition = p.availablePosition > 0; |
| | | wxColor color = !hasPosition ? COLOR_INVALID: COLOR_VALID; |
| | | data.push_back(wxVariant(MyColorText(p.securityName, color))); |
| | | if (!hasPosition) |
| | | { |
| | | data.push_back(wxVariant(MyColorText(p.marketInfo.rate,color))); |
| | | } |
| | | else { |
| | | wxString rateText = p.marketInfo.rate; |
| | | rateText.Replace("%", ""); |
| | | double rate; |
| | | rateText.ToCDouble(&rate); |
| | | wxColor tempColor; |
| | | |
| | | if (rate > 0.0001) { |
| | | tempColor = wxColor(255, 42, 7); |
| | | if (rate > 8.9) { |
| | | tempColor = wxColor(243, 143, 250); |
| | | } |
| | | } |
| | | else if (rate < 0.0001) { |
| | | tempColor = wxColor(0, 230, 0); |
| | | } |
| | | else { |
| | | tempColor = wxColor(64, 64, 64); |
| | | } |
| | | data.push_back(wxVariant(MyColorText(p.marketInfo.rate, tempColor))); |
| | | } |
| | | data.push_back(wxVariant(MyColorText(wxString(p.marketInfo.price),color))); |
| | | data.push_back(wxVariant(MyColorText(p.marketInfo.lastVolume, color))); |
| | | data.push_back(wxVariant(MyColorText(p.underlyingMarketInfo.rate, color))); |
| | | if (!hasPosition) |
| | | { |
| | | data.push_back(wxVariant(MyColorText(p.underlyingMarketInfo.buy1Money, color))); |
| | | } |
| | | else { |
| | | data.push_back(wxVariant(MyColorText(p.underlyingMarketInfo.buy1Money, wxColor(204, 78, 232)))); |
| | | } |
| | | |
| | | |
| | | // 计算持仓金额 |
| | | double positionMoney = 0.00; |
| | | if (p.marketInfo.price.Length() > 0) { |
| | | double price; |
| | | p.marketInfo.price.ToCDouble(&price); |
| | | positionMoney = price * p.currentPosition; |
| | | } |
| | | if (!hasPosition) { |
| | | data.push_back(wxVariant(MyColorText(StringUtil::to_string(positionMoney, 2),color))); |
| | | } |
| | | else { |
| | | data.push_back(wxVariant(MyColorText(StringUtil::to_string(positionMoney, 2), *wxRED))); |
| | | } |
| | | |
| | | |
| | | |
| | | // 成本价计算: 总买入金额 + 手续费 |
| | | double totalPosCost = 0; |
| | | int totalVolume = 0; |
| | | for (std::list<DealInfo>::iterator e = p.buyList.begin(); e != p.buyList.end(); e++) { |
| | | DealInfo info = *e; |
| | | string price = info.price.ToStdString(); |
| | | totalPosCost += stod(price.c_str()) * info.volume; |
| | | totalVolume += info.volume; |
| | | } |
| | | double todayCommission; |
| | | p.todayCommission.ToDouble(&todayCommission); |
| | | totalPosCost += todayCommission; |
| | | wxString cost_price = StringUtil::to_string(totalPosCost / totalVolume, 3); |
| | | data.push_back(wxVariant(MyColorText(cost_price, color))); |
| | | // 今日盈亏计算: 总卖出金额 + 持仓*现价 - 买入金额 - 手续费 |
| | | double totalSellMoney = 0; |
| | | for (std::list<DealInfo>::iterator e = p.sellList.begin(); e != p.sellList.end(); e++) { |
| | | double price; |
| | | (*e).price.ToDouble(&price); |
| | | totalSellMoney += price * (*e).volume; |
| | | } |
| | | double profit_money = totalSellMoney + positionMoney - totalPosCost; |
| | | |
| | | // 计算今日盈亏比 |
| | | double profit_rate = profit_money / totalPosCost; |
| | | wxString profit_rate_str = ""; |
| | | profit_rate_str.Append(StringUtil::to_string(profit_rate * 100)).Append("%"); |
| | | data.push_back(wxVariant(MyColorText(profit_rate_str, color))); |
| | | // 正股数据设置 |
| | | |
| | | if (hasPosition) { |
| | | data.push_back(wxVariant(MyButton( p.underlyingMarketInfo.code,"查看",wxColor(64,64,64), wxColor(225,225,225)))); |
| | | } |
| | | else { |
| | | data.push_back(wxVariant(MyButton(p.underlyingMarketInfo.code, "查看", color, wxColor(255,255,255)))); |
| | | } |
| | | data.push_back(wxVariant(MyColorText(wxString(to_string(p.currentPosition).c_str()),color))); |
| | | data.push_back(wxVariant(MyColorText(StringUtil::to_string(profit_money, 2), color))); |
| | | data.push_back(wxVariant(MyColorText(p.underlyingMarketInfo.name, color))); |
| | | |
| | | viewManager->positionWidgets->listCtrlReport->AppendItem(data); |
| | | if (selectPositionId == p.id) { |
| | | viewManager->positionWidgets->listCtrlReport->Select(viewManager->positionWidgets->listCtrlReport->RowToItem(index)); |
| | | // 设置tick的买点与卖点 |
| | | std::list<TickTradeData> tradePoints; |
| | | for (std::list<DealInfo>::iterator e = p.buyList.begin(); e != p.buyList.end(); ++e) { |
| | | DealInfo info = *e; |
| | | double price = stod(info.price.ToStdString().c_str()); |
| | | double rate = (price - p.marketInfo.preClosePrice) * 100 / p.marketInfo.preClosePrice; |
| | | tradePoints.push_back(TickTradeData({ info.tradeTime, (float)rate, info.price.ToStdString(), info.volume, StringUtil::to_string(info.volume * stod(info.price.ToStdString().c_str())) })); |
| | | } |
| | | viewManager->tickWidgets->tickChart->SetBuyPoint(tradePoints); |
| | | tradePoints.clear(); |
| | | for (std::list<DealInfo>::iterator e = p.sellList.begin(); e != p.sellList.end(); ++e) { |
| | | DealInfo info = *e; |
| | | double price = stod(info.price.ToStdString().c_str()); |
| | | double rate = (price - p.marketInfo.preClosePrice) * 100 / p.marketInfo.preClosePrice; |
| | | tradePoints.push_back(TickTradeData({ info.tradeTime, (float)rate, info.price.ToStdString(), info.volume, StringUtil::to_string(info.volume * stod(info.price.ToStdString().c_str())) })); |
| | | } |
| | | viewManager->tickWidgets->tickChart->SetSellPoint(tradePoints); |
| | | } |
| | | index += 1; |
| | | } |
| | | viewManager->positionWidgets->listCtrlReport->Refresh(); |
| | | } |
| | | |
| | | void MainFrame::requestMoney() |
| | | { |
| | | cout << "###########请求账户资金##########" << endl; |
| | | string result = MyNetworkApi::get_money(); |
| | | if (this == nullptr) { |
| | | return; |
| | | } |
| | | auto doc = JsonUtil::parseUTF16(result); |
| | | try { |
| | | if (doc.IsObject() && doc[L"code"].GetInt() == 0) { |
| | | auto array = doc[L"data"].GetArray(); |
| | | if (array.Size() > 0) |
| | | { |
| | | auto data = array[0].GetObject(); |
| | | viewManager->moneyWidgets->availableLabel->SetLabelText(StringUtil::to_string(data[L"usefulMoney"].GetDouble(), 2)); |
| | | viewManager->moneyWidgets->frozenLabel->SetLabelText(StringUtil::to_string(data[L"frozenCash"].GetDouble(), 2)); |
| | | } |
| | | } |
| | | } |
| | | catch (...) { |
| | | |
| | | |
| | | } |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | } |
| | | |
| | | void MainFrame::startRequestPositionsTask(MainFrame* context) |
| | | { |
| | | while (TRUE) { |
| | | try { |
| | | context->requestPositions(); |
| | | } |
| | | catch (...) { |
| | | } |
| | | Sleep(2000); |
| | | } |
| | | } |
| | | |
| | | void MainFrame::startRequestMoneyTask(MainFrame* context) |
| | | { |
| | | while (TRUE) { |
| | | try { |
| | | context->requestMoney(); |
| | | } |
| | | catch (...) { |
| | | } |
| | | Sleep(2000); |
| | | } |
| | | } |
| | | |
| | | void MainFrame::OnTickCallBack(CodeBasicInfo info, wxString xStartTime, wxString xEndTime, std::list<TickTradeData> buyPoints, std::list<TickTradeData> sellPoints, float costRate, void* context) |
| | | { |
| | | MainFrame* mainFrame = (MainFrame*)context; |
| | | |
| | | wxSize size = mainFrame->GetSize(); |
| | | |
| | | int width = size.GetWidth(); |
| | | width = width * 3 / 4; |
| | | int height = width * 2 / 3; |
| | | |
| | | |
| | | TickFrame* tickFrame = new TickFrame(mainFrame, info.codeName, info.code, info.codeName, info.preClosePrice, xStartTime, xEndTime, buyPoints, sellPoints, costRate, wxDefaultPosition, wxSize(width, height)); |
| | | tickFrame->Show(); |
| | | } |
| | | |
| | | LRESULT MainFrame::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam) |
| | | { |
| | | cout <<"MSWWindowProc:"<< nMsg << endl; |
| | | if (nMsg == WM_COPYDATA) { |
| | | COPYDATASTRUCT* pcds = (COPYDATASTRUCT*)lParam; |
| | | if (pcds != NULL) { |
| | | int action_code = pcds->dwData; |
| | | if (action_code == 100) { |
| | | // 卖 |
| | | BYTE* pBuf = (BYTE*)(pcds->lpData); |
| | | DWORD dwSize = (DWORD)(pcds->cbData); |
| | | std::string str(reinterpret_cast<const char*>(pBuf), dwSize); |
| | | // 在这里处理接收到的字符串数据 receivedData |
| | | cout << "内容:" << str << endl; |
| | | wxCommandEvent event; |
| | | this->OnBtnSellClick(event); |
| | | } |
| | | } |
| | | } |
| | | return wxFrame::MSWWindowProc(nMsg, wParam, lParam); |
| | | } |
| | | |
| | | void MainFrame::OnClose(wxCloseEvent& event) { |
| | | |
| | | killed = true; |
| | | MyConfigUtil::setMainWindowPos(GetPosition(), GetSize()); |
| | | // 保存持仓股列宽 |
| | | int columnCount = viewManager->positionWidgets->listCtrlReport->GetColumnCount(); |
| | | std::list<int> positionWidthList; |
| | | for (int i = 0; i < columnCount; i++) { |
| | | wxDataViewColumn* column = viewManager->positionWidgets->listCtrlReport->GetColumn(i); |
| | | int columnWidth = column->GetWidth(); |
| | | positionWidthList.push_back(columnWidth); |
| | | } |
| | | MyConfigUtil::setPositionColumnWidth(positionWidthList); |
| | | event.Skip(); |
| | | exit(0); |
| | | } |
| | | |
| | | void MainFrame::OnBtnRefreshClick(wxCommandEvent& event) |
| | | { |
| | | string result = MyNetworkApi::refresh_position(); |
| | | cout << "刷新持仓结果:" << result.c_str() << endl; |
| | | result = MyNetworkApi::refresh_deal(); |
| | | cout << "刷新成交结果:" << result.c_str() << endl; |
| | | |
| | | |
| | | |
| | | } |
| | | |
| | | void MainFrame::OnBtnBuyClick(wxCommandEvent& event) |
| | | { |
| | | if (!selectPositionId || selectPositionId.length() == 0) { |
| | | showMsg("尚未选中持仓", MSG_TYPE_WARNING); |
| | | return; |
| | | } |
| | | |
| | | PositionInfo pos = getSeclectedPosition(); |
| | | wxString code = viewManager->topWidgets->codeEdit->GetValue(); |
| | | wxString buyMoney = viewManager->sellWidgets->buyMoney->GetValue(); |
| | | if (buyMoney.length() <= 0) { |
| | | showMsg("请输入买入金额", MSG_TYPE_WARNING); |
| | | return; |
| | | } |
| | | int priceType = viewManager->sellWidgets->buyPrice->GetSelection(); |
| | | // 通过金额计算卖的量 |
| | | double volume = stoi(buyMoney.ToStdString().c_str()) / stod(pos.marketInfo.price.ToStdString().c_str()); |
| | | int volume_int = (int)volume; |
| | | volume_int = volume_int / 10 * 10; |
| | | if (volume_int <= 0) { |
| | | showMsg("买入小于10股", MSG_TYPE_WARNING); |
| | | return; |
| | | } |
| | | |
| | | string result = MyNetworkApi::buy(code.ToStdString(), priceType, volume_int); |
| | | |
| | | auto doc = JsonUtil::parseUTF16(result); |
| | | if (doc.IsObject()) { |
| | | if (doc[L"code"].GetInt() == 0) { |
| | | auto data = doc[L"data"].GetObject(); |
| | | if (data.HasMember(L"orderStatus") && data[L"orderStatus"].GetInt() == -1) { |
| | | showMsg(data[L"orderStatusMsg"].GetString(), MSG_TYPE_ERROR); |
| | | } |
| | | else { |
| | | showMsg("买入成功", MSG_TYPE_INFO); |
| | | requestPositions(); |
| | | } |
| | | } |
| | | else { |
| | | showMsg(doc[L"msg"].GetString(), MSG_TYPE_ERROR); |
| | | } |
| | | } |
| | | else { |
| | | showMsg("网络请求出错", MSG_TYPE_ERROR); |
| | | } |
| | | } |
| | | |
| | | |
| | | void MainFrame::showMsg(wxString msg, MsgTypeEnum type) |
| | | { |
| | | // 显示15s |
| | | msgExpireTime = TimeUtil::getNowTimeStamp() + MSG_SHOW_TIME; |
| | | switch (type) |
| | | { |
| | | case MSG_TYPE_ERROR: |
| | | viewManager->topWidgets->msgLabel->SetForegroundColour(*wxGREEN); |
| | | break; |
| | | case MSG_TYPE_WARNING: |
| | | viewManager->topWidgets->msgLabel->SetForegroundColour(*wxGREEN); |
| | | break; |
| | | case MSG_TYPE_INFO: |
| | | viewManager->topWidgets->msgLabel->SetForegroundColour(*wxBLACK); |
| | | break; |
| | | default: |
| | | break; |
| | | } |
| | | viewManager->topWidgets->msgLabel->SetLabelText(msg); |
| | | // 启动线程结束显示 |
| | | thread t(clearMsg, this); |
| | | t.detach(); |
| | | } |
| | | |
| | | |
| | | void MainFrame::clearMsg(MainFrame* context) |
| | | { |
| | | Sleep(MSG_SHOW_TIME); |
| | | if (TimeUtil::getNowTimeStamp() > context->msgExpireTime) { |
| | | context->viewManager->topWidgets->msgLabel->SetLabelText(""); |
| | | } |
| | | } |
| | | |
| | | void MainFrame::runJueJinStrategy(MainFrame* context) |
| | | { |
| | | context->tickDataRequestStrategy->run(); |
| | | while (TRUE) { |
| | | Sleep(3000); |
| | | } |
| | | } |
| | | |
| | | void MainFrame::tickDataCallback(Tick* tick, void* context) |
| | | { |
| | | string symbol = tick->symbol; |
| | | symbol = symbol.substr(symbol.find(".") + 1, 6); |
| | | cout << "回调:" << symbol << endl; |
| | | MainFrame* that = (MainFrame*)context; |
| | | for (std::list<PositionInfo>::iterator e = that->positionList.begin(); e != that->positionList.end(); e++) { |
| | | PositionInfo info = *e; |
| | | if (that->selectPositionId == info.id) { |
| | | if (info.securityID == symbol) |
| | | { |
| | | that->viewManager->tickWidgets->tickChart->AddTickData(TimeUtil::format((long)tick->created_at, "%H:%M:%S"), 100 * (tick->price - info.marketInfo.preClosePrice) / info.marketInfo.preClosePrice, to_string(tick->price)); |
| | | } |
| | | else if (info.underlyingMarketInfo.code == symbol) { |
| | | that->viewManager->tickWidgets->tickChart->AddUnderlyingTickData(TimeUtil::format((long)tick->created_at, "%H:%M:%S"), 100 * (tick->price - info.underlyingMarketInfo.preClosePrice) / info.underlyingMarketInfo.preClosePrice); |
| | | } |
| | | break; |
| | | } |
| | | } |
| | | } |
| | | |
| | | PositionInfo MainFrame::getSeclectedPosition() |
| | | { |
| | | for (list<PositionInfo>::iterator e = positionList.begin(); e != positionList.end(); ++e) { |
| | | PositionInfo info = *e; |
| | | if (info.id == selectPositionId) { |
| | | return info; |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | void MainFrame::OnBtnSellClick(wxCommandEvent& event) |
| | | { |
| | | if (!selectPositionId || selectPositionId.length() == 0) { |
| | | showMsg("尚未选中持仓", MSG_TYPE_WARNING); |
| | | return; |
| | | } |
| | | |
| | | PositionInfo pos = getSeclectedPosition(); |
| | | wxString code = viewManager->topWidgets->codeEdit->GetValue(); |
| | | wxString sellMoney = viewManager->sellWidgets->sellMoney->GetValue(); |
| | | if (sellMoney.length() <= 0) { |
| | | showMsg("请输入卖金额", MSG_TYPE_WARNING); |
| | | return; |
| | | } |
| | | int priceType = viewManager->sellWidgets->sellPrice->GetSelection(); |
| | | |
| | | // 通过金额计算卖的量 |
| | | double volume = stoi(sellMoney.ToStdString().c_str()) / stod(pos.marketInfo.price.ToStdString().c_str()); |
| | | int volume_int = (int)volume; |
| | | volume_int = volume_int / 10 * 10; |
| | | cout << "卖出的量:" << volume_int << endl; |
| | | if (volume_int > pos.availablePosition) { |
| | | volume_int = pos.availablePosition; |
| | | } |
| | | string result = MyNetworkApi::sell(code.ToStdString(), priceType, volume_int); |
| | | auto doc = JsonUtil::parseUTF16(result); |
| | | if (doc.IsObject()) { |
| | | if (doc[L"code"].GetInt() == 0) { |
| | | auto data = doc[L"data"].GetObject(); |
| | | if (data.HasMember(L"orderStatus") && data[L"orderStatus"].GetInt() == -1) { |
| | | showMsg(data[L"orderStatusMsg"].GetString(), MSG_TYPE_ERROR); |
| | | } |
| | | else { |
| | | showMsg("卖出成功", MSG_TYPE_INFO); |
| | | requestPositions(); |
| | | } |
| | | } |
| | | else { |
| | | showMsg(doc[L"msg"].GetString(), MSG_TYPE_ERROR); |
| | | } |
| | | } |
| | | else { |
| | | showMsg("网络请求出错", MSG_TYPE_ERROR); |
| | | } |
| | | } |
| | | |
| | | void MainFrame::OnPositionSelectionChanged(wxDataViewEvent& event) |
| | | { |
| | | auto item = viewManager->positionWidgets->listCtrlReport->GetSelection(); |
| | | int rowIndex = viewManager->positionWidgets->listCtrlReport->ItemToRow(item); |
| | | std::list<PositionInfo>::iterator e = positionList.begin(); |
| | | if (rowIndex > 0) { |
| | | std::advance(e, rowIndex); |
| | | } |
| | | if (rowIndex >= 0) |
| | | { |
| | | PositionInfo p = *e; |
| | | selectPositionId = p.id; |
| | | // 设置内容 |
| | | this->viewManager->topWidgets->codeEdit->SetValue(p.securityID); |
| | | |
| | | |
| | | |
| | | this->viewManager->tickWidgets->tickChart->Init(CodeBasicInfo({ p.securityID ,p.marketInfo.name,p.marketInfo.preClosePrice }), CodeBasicInfo({ p.underlyingMarketInfo.code ,p.underlyingMarketInfo.name,p.underlyingMarketInfo.preClosePrice }), this, MainFrame::OnTickCallBack); |
| | | |
| | | float costRate = DataParseUtil::computeCostRate(p); |
| | | this->viewManager->tickWidgets->tickChart->SetCostRate(p.securityID, costRate, ""); |
| | | |
| | | for (std::list<DealInfo>::iterator e = p.buyList.begin(); e != p.buyList.end(); ++e) { |
| | | DealInfo info = *e; |
| | | double price = stod(info.price.ToStdString().c_str()); |
| | | double rate = (price - p.marketInfo.preClosePrice) * 100 / p.marketInfo.preClosePrice; |
| | | this->viewManager->tickWidgets->tickChart->AddBuyPoint(info.tradeTime, rate, info.price.ToStdString(), info.volume, StringUtil::to_string(info.volume * stod(info.price.ToStdString().c_str()))); |
| | | } |
| | | for (std::list<DealInfo>::iterator e = p.sellList.begin(); e != p.sellList.end(); ++e) { |
| | | DealInfo info = *e; |
| | | double price = stod(info.price.ToStdString().c_str()); |
| | | double rate = (price - p.marketInfo.preClosePrice) * 100 / p.marketInfo.preClosePrice; |
| | | this->viewManager->tickWidgets->tickChart->AddSellPoint(info.tradeTime, rate, info.price.ToStdString(), info.volume, StringUtil::to_string(info.volume * stod(info.price.ToStdString().c_str()))); |
| | | } |
| | | |
| | | |
| | | wxRichTextAttr style; |
| | | wxRichTextCtrl *richText = this->viewManager->tickWidgets->codeInfoLabel; |
| | | richText->GetBuffer().Clear(); |
| | | richText->Clear(); |
| | | |
| | | //设置值 |
| | | wxString codeInfoStr = ""; |
| | | codeInfoStr.Append(p.underlyingMarketInfo.code).Append("(").Append(p.underlyingMarketInfo.name).Append("),"); |
| | | richText->WriteText(codeInfoStr); |
| | | codeInfoStr = ""; |
| | | |
| | | |
| | | style.SetTextColour(*wxRED); |
| | | richText->BeginStyle(style); |
| | | |
| | | richText->WriteText("【涨停原因:"); |
| | | richText->WriteText(p.underlyingDetailInfo.limitUpReason); |
| | | codeInfoStr.Append("&板块身位:"); |
| | | int i = 0; |
| | | for (std::list<CodeBlockInfo>::iterator e = p.underlyingDetailInfo.blockInfos.begin(); e != p.underlyingDetailInfo.blockInfos.end(); ++e) { |
| | | CodeBlockInfo info = *e; |
| | | codeInfoStr.Append(info.name).Append("-").Append(to_string(info.rank)); |
| | | i++; |
| | | if (i != p.underlyingDetailInfo.blockInfos.size()) { |
| | | codeInfoStr.Append("、"); |
| | | } |
| | | } |
| | | codeInfoStr.Append("】"); |
| | | richText->WriteText(codeInfoStr); |
| | | richText->EndStyle(); |
| | | style.SetTextColour(*wxBLACK); |
| | | |
| | | |
| | | |
| | | codeInfoStr = ""; |
| | | codeInfoStr.Append(",板块:"); |
| | | |
| | | |
| | | |
| | | auto blocks = p.underlyingDetailInfo.blocks; |
| | | i = 0; |
| | | for (std::list<wxString>::iterator e = blocks.begin(); e != blocks.end(); ++e) { |
| | | codeInfoStr.Append(*e); |
| | | i++; |
| | | if (i != blocks.size()) { |
| | | codeInfoStr.Append("/"); |
| | | } |
| | | } |
| | | codeInfoStr.Append(","); |
| | | codeInfoStr.Append("时间:").Append(p.underlyingDetailInfo.limit_up_time).Append(","); |
| | | codeInfoStr.Append("市场身位:").Append(p.underlyingDetailInfo.highDesc).Append(","); |
| | | codeInfoStr.Append("板块数量:"); |
| | | i = 0; |
| | | for (std::list<CodeBlockInfo>::iterator e = p.underlyingDetailInfo.blockInfos.begin(); e != p.underlyingDetailInfo.blockInfos.end(); ++e) { |
| | | CodeBlockInfo info = *e; |
| | | wxString s = "&"; |
| | | codeInfoStr.Append(info.name).Append(s).Append(to_string(info.totalLimitUpCount)).Append(s).Append(to_string(info.openLimitUpCount)); |
| | | i++; |
| | | if (i != p.underlyingDetailInfo.blockInfos.size()) { |
| | | codeInfoStr.Append("、"); |
| | | } |
| | | } |
| | | codeInfoStr.Append(","); |
| | | |
| | | |
| | | |
| | | codeInfoStr.Append("市值:").Append(p.underlyingDetailInfo.zyltgb).Append(","); |
| | | codeInfoStr.Append("股价:").Append(p.underlyingDetailInfo.price).Append(","); |
| | | codeInfoStr.Append("大单成交:").Append(p.underlyingDetailInfo.bigOrderDealMoney).Append("-").Append(to_string(p.underlyingDetailInfo.bigOrderDealCount)).Append("笔"); |
| | | |
| | | richText->WriteText(codeInfoStr); |
| | | |
| | | tickDataRequestStrategy->subscribeSymbol(JueJinDataUtil::getSymbol(p.securityID.ToStdString()), JueJinDataUtil::getSymbol(p.underlyingMarketInfo.code.ToStdString())); |
| | | } |
| | | else { |
| | | selectPositionId = ""; |
| | | } |
| | | cout << "选中的行:" << rowIndex << endl; |
| | | |
| | | event.Skip(); |
| | | //event.Veto(); |
| | | } |
| | | |
| | | void MainFrame::OnBtnBackTest(wxCommandEvent& event) |
| | | { |
| | | wxString date = viewManager->topWidgets->backTestDate->GetValue(); |
| | | wxString btnValue = viewManager->topWidgets->btnBackTest->GetLabelText(); |
| | | try { |
| | | if (btnValue.StartsWith("开始")) { |
| | | string result = MyNetworkApi::set_backtest_mode(date.ToStdString(), true); |
| | | auto doc = JsonUtil::parseUTF16(result); |
| | | if (!doc.IsObject()) { |
| | | throw wxString("网络请求出错"); |
| | | } |
| | | if (doc[L"code"].GetInt() != 0) { |
| | | throw wxString(doc[L"msg"].GetString()); |
| | | } |
| | | viewManager->topWidgets->btnBackTest->SetLabelText("结束回测"); |
| | | } |
| | | else { |
| | | string result = MyNetworkApi::set_backtest_mode(date.ToStdString(), false); |
| | | auto doc = JsonUtil::parseUTF16(result); |
| | | if (!doc.IsObject()) { |
| | | throw wxString("网络请求出错"); |
| | | } |
| | | if (doc[L"code"].GetInt() != 0) { |
| | | throw wxString(doc[L"msg"].GetString()); |
| | | } |
| | | viewManager->topWidgets->btnBackTest->SetLabelText("开始回测"); |
| | | } |
| | | } |
| | | catch (wxString st) { |
| | | wxMessageBox(st); |
| | | } |
| | | catch (...) { |
| | | wxMessageBox(L"网络请求出错"); |
| | | } |
| | | |
| | | |
| | | |
| | | } |