admin
2024-07-05 3ef188e6075649f4c72e3e7588d8966e1071f2ff
CBTrade/MainFrame.cpp
@@ -4,17 +4,48 @@
#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);
}
@@ -24,4 +55,747 @@
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"网络请求出错");
   }
}