#include "TickChart.h" #include "../common_nopch/StringUtil.h" #include "../common_nopch/TimeUtil.h" #include "TickDataUtil.h" #include "JueJinDataUtil.h" #include using namespace std; #define COLOR_RED wxColor(128,0,0) #define COLOR_RED_TEXT wxColor(225,0,0) #define COLOR_GREEN_TEXT wxColor(0,225,0) #define COLOR_WHITE_TEXT wxColor(255,255,255) #define COLOR_YELLOW wxColor(255,128,32) #define COLOR_UNDERLYING_LINE wxColor(133,202,255) // Õ¤¸ñÏßÊýÁ¿ #define GRID_LINE_ROW_COUNT 15 #define GRID_LINE_COL_COUNT 9 #define GRID_MARGIN Padding({ 60,20,50,25}) #define MAX_RATE_FLOAT 0.7 #define POINT_REDIUS 2 wxPoint TickChart::convertTickDataToPoint(TickData tickData, wxRect area, float scale) { int X_COUNT = this->xScopeSeconds / this->timeSpace;// 4Сʱ5·ÖÖÓÄÒÀ¨µÄËùÓеã int width = (tickData.time / this->timeSpace) * (area.width - GRID_MARGIN.left - GRID_MARGIN.right) / X_COUNT; int x = area.x + GRID_MARGIN.left + width; int y = area.y + GRID_MARGIN.top + (area.height - GRID_MARGIN.top - GRID_MARGIN.bottom) * (maxYRate - tickData.rate * scale) / (maxYRate * 2); return wxPoint(x, y); } wxPoint TickChart::convertTickDataToPoint(TickTradeData tickData, wxRect area) { int X_COUNT = this->xScopeSeconds / this->timeSpace;// Õû¸öXÖáµÄËùÓеã int width = (TickDataUtil::timeStrToSecondsAsAxisX(tickData.time, xStartTimeSeconds) / this->timeSpace) * (area.width - GRID_MARGIN.left - GRID_MARGIN.right) / X_COUNT; int x = area.x + GRID_MARGIN.left + width; int y = area.y + GRID_MARGIN.top + (area.height - GRID_MARGIN.top - GRID_MARGIN.bottom) * (maxYRate - tickData.rate) / (maxYRate * 2); return wxPoint(x, y); } TickData TickChart::pointToTick(wxPoint point, wxRect area) { // ¾àÀë×ó±ßÔµ±ßµÄ¾àÀë int x = point.x - area.x - GRID_MARGIN.left; int y = point.y - area.y - GRID_MARGIN.top; int width = area.GetWidth() - GRID_MARGIN.left - GRID_MARGIN.right; int height = area.GetHeight() - GRID_MARGIN.top - GRID_MARGIN.bottom; int seconds = x * this->xScopeSeconds / width; seconds = seconds / this->timeSpace * this->timeSpace; // ½«Ê±¼äsתΪ×Ö·û´® float rate = maxYRate - y * maxYRate * 2 / height; TickData tickData; tickData.rate = rate; tickData.time = seconds; tickData.price = ""; return tickData; } void TickChart::drawAxis(wxDC& dc, wxRect area) { //WidgetsRenderUtil::drawText(dc, "²âÊÔ123", wxPoint(area.x, area.y), 100,50); Padding padding = GRID_MARGIN; // »æÖÆÕ¤¸ñ int row_line_count = GRID_LINE_ROW_COUNT; int column_line_count = GRID_LINE_COL_COUNT; list grides_rows; double rowSpace = (area.height - padding.top - padding.bottom) / ((row_line_count - 1) * 1.0f); for (int i = 0; i < row_line_count; i++) { // »æÖƺáÏòÕ¤¸ñ LineInfo* lineInfo = new LineInfo(); lineInfo->lineWidth = 1; if (i == row_line_count / 2) { lineInfo->lineWidth = 3; } lineInfo->style = wxPENSTYLE_SOLID; lineInfo->start = wxPoint(area.x + padding.left, area.y + padding.top + (int)(rowSpace * (i)) - lineInfo->lineWidth / 2); lineInfo->end = wxPoint(area.x + area.width - padding.right, area.y + padding.top + (int)(rowSpace * (i)) - lineInfo->lineWidth / 2); grides_rows.push_back(lineInfo); } for (list::iterator e = grides_rows.begin(); e != grides_rows.end(); ++e) { try { LineInfo* lineInfo = *e; wxPen dashedPen(COLOR_RED, lineInfo->lineWidth, lineInfo->style); dc.SetPen(dashedPen); dc.DrawLine(lineInfo->start, lineInfo->end); } catch (...) { } } list grides_cols; double columnSpace = (area.width - padding.left - padding.right) / ((column_line_count - 1) * 1.0f); for (int i = 0; i < column_line_count; i++) { // »æÖƺáÏòÕ¤¸ñ LineInfo* lineInfo = new LineInfo(); lineInfo->lineWidth = 1; lineInfo->start = wxPoint(area.x + padding.left + (int)(columnSpace * (i)), area.y + padding.top); lineInfo->end = wxPoint(area.x + padding.left + (int)(columnSpace * (i)), area.y + area.height - padding.bottom - 1); if (i % 2 == 1) { lineInfo->style = wxPENSTYLE_DOT; } else { lineInfo->style = wxPENSTYLE_SOLID; } if (i == column_line_count / 2) { lineInfo->lineWidth = 2; } grides_cols.push_back(lineInfo); } for (list::iterator e = grides_cols.begin(); e != grides_cols.end(); ++e) { try { LineInfo* lineInfo = *e; wxPen dashedPen(COLOR_RED, lineInfo->lineWidth, lineInfo->style); dc.SetPen(dashedPen); dc.DrawLine(lineInfo->start, lineInfo->end); } catch (...) { } } //---------------»æÖÆLabel------------------- AxisYLabel ylabels[GRID_LINE_ROW_COUNT]; const int UP_COUNT = (GRID_LINE_ROW_COUNT - 1) / 2; for (int i = 0; i < GRID_LINE_ROW_COUNT; i++) { AxisYLabel label; float rate = (UP_COUNT - i) * maxYRate / UP_COUNT; label.rightLabel = StringUtil::toString(abs(rate), 2).append("%"); label.leftLabel = StringUtil::toString((100 + rate) * preClosePrice / 100, 3); ylabels[i] = AxisYLabel(label); } dc.SetPen(COLOR_RED); dc.SetBrush(COLOR_RED); wxPen dashedPen(COLOR_RED, 1, wxPENSTYLE_SOLID); dc.SetPen(dashedPen); int index = 0; for (list::iterator e = grides_rows.begin(); e != grides_rows.end(); ++e) { if (index == 0) { dc.SetTextForeground(COLOR_RED_TEXT); } else if (index == grides_rows.size() / 2) { dc.SetTextForeground(COLOR_WHITE_TEXT); } else if (index == grides_rows.size() / 2 + 1) { dc.SetTextForeground(COLOR_GREEN_TEXT); } try { LineInfo* lineInfo = *e; // »æÖÆYÖá×ó²à±êÇ© wxSize textSize = dc.GetTextExtent(ylabels[index].leftLabel); dc.DrawText(ylabels[index].leftLabel, wxPoint(lineInfo->start.x - textSize.GetWidth() - 2, lineInfo->start.y - textSize.GetHeight() / 2)); // »æÖÆYÖáÓÒ²à±êÇ© textSize = dc.GetTextExtent(ylabels[index].rightLabel); dc.DrawText(ylabels[index].rightLabel, wxPoint(lineInfo->end.x + 2, lineInfo->end.y - textSize.GetHeight() / 2)); } catch (...) { } index++; } // »æÖÆÊ±¼ä dc.SetTextForeground(COLOR_RED_TEXT); if (timeSpaceType == TIME_SPACE_BAR) { wxString times[5] = { "09:30:00","10:30:00","11:30:00","14:00:00","15:00:00" }; for (int i = 0; i < 5; i++) { wxPoint p = convertTickDataToPoint(TickData({ TickDataUtil::timeStrToSecondsAsAxisX(times[i], xStartTimeSeconds) ,0,"" }), area); wxString text = times[i].substr(0, 5); wxSize size = dc.GetTextExtent(text); wxPoint point(p.x - size.GetWidth() / 2, area.y + area.height - GRID_MARGIN.bottom + 2); dc.DrawText(text, point); } } else if (timeSpaceType == TIME_SPACE_TICK) { int spaceSeconds = this->xScopeSeconds / 4; wxString times[5]; times[0] = xStartTime; for (int i = 0; i < 5; i++) { times[i] = TickDataUtil::tradTimeAdd(xStartTime, this->xScopeSeconds * i / 4); } for (int i = 0; i < 5; i++) { wxPoint p = convertTickDataToPoint(TickData({ TickDataUtil::timeStrToSecondsAsAxisX(times[i], xStartTimeSeconds) ,0,"" }), area); wxString text = times[i]; wxSize size = dc.GetTextExtent(text); wxPoint point(p.x - size.GetWidth() / 2, area.y + area.height - GRID_MARGIN.bottom + 2); dc.DrawText(text, point); } } } void TickChart::drawMouse(wxDC& dc, wxRect area, wxPoint point) { int x = mousePos.x; int y = mousePos.y; if (x >= area.x + GRID_MARGIN.left && x <= area.x + area.width - GRID_MARGIN.right) { if (y >= area.y + GRID_MARGIN.top && y <= area.y + area.height - GRID_MARGIN.bottom) { if (point.x >= 0 && point.y >= 0) { TickData tickData = pointToTick(point, area); dc.SetPen(COLOR_WHITE_TEXT); // ºáÏß dc.DrawLine(wxPoint(area.x + GRID_MARGIN.left, area.y + point.y), wxPoint(area.x + area.width - GRID_MARGIN.right, area.y + point.y)); // ÊúÏß dc.DrawLine(wxPoint(area.x + point.x, area.y + GRID_MARGIN.top), wxPoint(area.x + point.x, area.y + area.height - GRID_MARGIN.bottom)); // »æÖÆÊ±¼ä wxPoint timePoint = wxPoint(area.x + point.x, area.y + area.height - GRID_MARGIN.bottom); wxString timeText = TickDataUtil::axisXSecondsToTimeStr(tickData.time, xStartTimeSeconds, timeSpaceType == TIME_SPACE_TICK ? TRUE : FALSE); wxSize size = dc.GetTextExtent(timeText); timePoint.x -= size.GetWidth() / 2; timePoint.y += 1; dc.SetPen(wxColor(64, 0, 128)); dc.SetBrush(wxColor(64, 0, 128)); // ÏÔʾʱ¼ä dc.DrawRectangle(wxRect(timePoint, size)); dc.SetTextForeground(COLOR_RED_TEXT); dc.DrawLabel(timeText, wxRect(timePoint, size), wxALIGN_CENTER); // ÏÔʾ±ÈÀý float rate = tickData.rate; string rateText = StringUtil::to_string(tickData.rate, 2); rateText.append("%"); size = dc.GetTextExtent(rateText); wxPoint ratePoint = wxPoint(area.x + area.width - GRID_MARGIN.right, area.y + point.y); ratePoint.y -= size.GetHeight() / 2; ratePoint.x += 1; dc.DrawRectangle(wxRect(ratePoint, size)); int r = (int)round(rate * 10000) / 100; if (r == 0) { dc.SetTextForeground(COLOR_WHITE_TEXT); } else if (r > 0) { dc.SetTextForeground(COLOR_RED_TEXT); } else { dc.SetTextForeground(COLOR_GREEN_TEXT); } dc.DrawLabel(rateText, wxRect(ratePoint, size), wxALIGN_CENTER); } } } } void TickChart::drawTickLine(wxDC& dc, wxRect area) { // ---------------»æÖÆKÏß---------------- int index = 0; wxPointList pointList; dc.SetPen(COLOR_WHITE_TEXT); for (std::list::iterator e = cbTickDatas.begin(); e != cbTickDatas.end(); e++) { //µã¶¨Î»×ø±ê TickData tickData = *e; wxPoint point = convertTickDataToPoint(tickData, area); pointList.Append(new wxPoint(point.x, point.y)); index++; } dc.DrawLines(&pointList); //ÊͷŵãÄÚ´æ pointList.Clear(); } void TickChart::drawUnderlyingTickLine(wxDC& dc, wxRect area) { // ---------------»æÖÆ¹ÉÆ±KÏß---------------- int index = 0; wxPointList pointList; dc.SetPen(COLOR_UNDERLYING_LINE); for (std::list::iterator e = underlyingTickDatas.begin(); e != underlyingTickDatas.end(); e++) { //µã¶¨Î»×ø±ê TickData tickData = *e; wxPoint point = convertTickDataToPoint(tickData, area, underlyingScale); pointList.Append(new wxPoint(point.x, point.y)); index++; } dc.DrawLines(&pointList); //ÊͷŵãÄÚ´æ pointList.Clear(); } void TickChart::drawBuyPoint(wxDC& dc, wxPoint point) { dc.DrawCircle(point, POINT_REDIUS); } void TickChart::drawSellPoint(wxDC& dc, wxPoint point) { dc.SetPen(wxColor(59, 123, 191)); dc.SetBrush(wxColor(59, 123, 191)); dc.DrawCircle(point, POINT_REDIUS); } void TickChart::drawBuyAndSellPointInfo(wxDC& paint, wxRect area, wxPoint mousePoint) { paint.SetPen(wxColour(255, 255, 255, 125)); paint.SetBrush(wxColour(255, 255, 255, 125)); // Èç¹ûÔÚÂòµãÖÜΧ4¸öÏñËØ // »æÖÆÂòÂôµã for (std::list::iterator e = buyPoints.begin(); e != buyPoints.end(); e++) { TickTradeData tickData = *e; wxPoint point = convertTickDataToPoint(*e, area); if (abs(mousePoint.x - point.x) < POINT_REDIUS * 2 && abs(mousePoint.y - point.y) < POINT_REDIUS * 2) { // ¼ÆËãλÖà wxString text = wxString("³É½»Ê±¼ä£º").Append(tickData.time).Append("\n"); text.Append("ÕÇ·ù£º").Append(StringUtil::to_string(tickData.rate)).Append("%").Append("\n"); text.Append("³É½»¼Û£º").Append(StringUtil::to_string( stod( tickData.price.ToStdString().c_str()),3)).Append("Ôª\n"); text.Append("³É½»Á¿£º").Append(to_string(tickData.volume)).Append("\n"); text.Append("³É½»¶î£º").Append(tickData.money).Append("Ôª"); drawInfo(paint, wxPoint(point.x + POINT_REDIUS, point.y + POINT_REDIUS), text, {}); break; } } for (std::list::iterator e = sellPoints.begin(); e != sellPoints.end(); e++) { TickTradeData tickData = *e; wxPoint point = convertTickDataToPoint(*e, area); if (abs(mousePoint.x - point.x) < POINT_REDIUS * 2 && abs(mousePoint.y - point.y) < POINT_REDIUS * 2) { wxString text = wxString("³É½»Ê±¼ä£º").Append(tickData.time).Append("\n"); text.Append("ÕÇ·ù£º").Append(StringUtil::to_string(tickData.rate)).Append("%").Append("\n"); text.Append("³É½»¼Û£º").Append(StringUtil::to_string(stod(tickData.price.ToStdString().c_str()), 3)).Append("Ôª\n"); text.Append("³É½»Á¿£º").Append(to_string(tickData.volume)).Append("\n"); text.Append("³É½»¶î£º").Append(tickData.money).Append("Ôª"); drawInfo(paint, wxPoint(point.x + POINT_REDIUS, point.y + POINT_REDIUS), text, {}); break; } } } void TickChart::drawInfo(wxDC& paint, wxPoint position, wxString content, std::list colorIndexes) { std::vector substrings; size_t start = 0; size_t end = content.find("\n"); while (end != std::string::npos) { substrings.push_back(content.substr(start, end - start)); start = end + 1; end = content.find("\n", start); } substrings.push_back(content.substr(start, end)); int maxWidth = 0; int lineHeight = 0; for (std::vector::iterator e = substrings.begin(); e != substrings.end(); ++e) { wxString text = *e; wxSize size = paint.GetTextExtent(text); if (size.GetWidth() > maxWidth) { maxWidth = size.GetWidth(); } if (size.GetHeight() > lineHeight) { lineHeight = size.GetHeight(); } } int padding = 2; wxRect rect = wxRect(wxPoint(position.x, position.y), wxSize(maxWidth + padding * 2, lineHeight * substrings.size())); paint.DrawRoundedRectangle(rect, 2); std::list colors; WidgetsRenderUtil::drawText(&paint, content, wxPoint(rect.GetPosition().x + padding, rect.GetPosition().y), rect.GetSize().GetWidth() - padding * 2, lineHeight, colorIndexes); } void TickChart::drawUnderlyingLatestRate(wxDC& paint, wxRect area) { if (1 > 0) { return; } if (underlyingTickDatas.size() > 0) { // »æÖÆTickÏß×îеĵã TickData lastTickData = underlyingTickDatas.back(); wxPoint point = convertTickDataToPoint(lastTickData, area, underlyingScale); // »æÖÆÎÄ×Ö wxString rateText = " Õý¹É£º"; if (lastTickData.rate < 0) { paint.SetTextForeground(COLOR_GREEN_TEXT); rateText.Append(StringUtil::to_string(lastTickData.rate)); rateText.Append("%"); } else { paint.SetTextForeground(COLOR_RED_TEXT); rateText.Append(L"+"); rateText.Append(StringUtil::to_string(lastTickData.rate)); rateText.Append("%"); } rateText.Append(" "); wxSize rateSize = paint.GetTextExtent(rateText); int x = area.x + area.GetWidth() - rateSize.GetWidth()- GRID_MARGIN.right; int y = area.y + area.GetHeight() - rateSize.GetHeight() - GRID_MARGIN.bottom; paint.DrawRoundedRectangle(wxPoint(x, y), rateSize, 0); paint.DrawText(rateText, wxPoint(x,y)); } } void TickChart::drawUnderlyingQuotes(wxDC& paint, wxRect area) { if (underlyingTickDatas.size() <= 0) { return; } TickData tick = underlyingTickDatas.back(); if (tick.quotes.size() <= 0) { return; } wxSize size = paint.GetTextExtent("Íò"); int lineHeight = (int)(size.GetHeight() * 1.1); int contentHeight = size.GetHeight(); int contentWidth = contentHeight * 3; int height = lineHeight*10; int width = contentWidth * 2; // »æÖÆÂòÂôµµ¿Ú wxPoint middlePoint = wxPoint(area.GetLeft()+ GRID_MARGIN.left, area.GetBottom() - GRID_MARGIN.bottom - height/2); if (stoi(TimeUtil::format(TimeUtil::getNowTimeStamp(), "%H%M%S").c_str())<120000) { middlePoint.x = area.GetRight() - GRID_MARGIN.right - width; } wxColour textColor = wxColor(100, 100, 100); paint.SetBrush(wxColor(255,255,255,128)); paint.SetPen(*wxTRANSPARENT_PEN); paint.SetTextForeground(textColor); //paint.DrawRoundedRectangle(wxRect(wxPoint(middlePoint.x, middlePoint.y - height/2), wxSize(width, height)),5); int index = 0; for (std::list::iterator e = tick.quotes.begin(); e != tick.quotes.end(); ++e) { Quote qu = *e; // »æÖÆÂò wxString price; wxString money; if (qu.bid_volume > 0) { // ÓÐÂò1 price = wxString(StringUtil::to_string(qu.bid_price).c_str()); money = StringUtil::to_string( qu.bid_price * qu.bid_volume/10000,1); money.Append("Íò"); } else { price = "-"; money = "-"; } paint.DrawLabel(price, wxRect(wxPoint(middlePoint.x, middlePoint.y + lineHeight * index), wxSize(contentWidth, contentHeight)), wxALIGN_LEFT); paint.DrawLabel(money, wxRect(wxPoint(middlePoint.x + contentWidth, middlePoint.y + lineHeight * index), wxSize(contentWidth, contentHeight)), wxALIGN_RIGHT); // »æÖÆÂô if (qu.ask_price > 0) { // ÓÐÂò1 price = wxString(StringUtil::to_string(qu.ask_price).c_str()); money = StringUtil::to_string(qu.ask_price * qu.ask_volume / 10000, 1); money.Append("Íò"); } else { price = "-"; money = "-"; } paint.DrawLabel(price, wxRect(wxPoint(middlePoint.x, middlePoint.y - lineHeight * (index+1)), wxSize(contentWidth, contentHeight)), wxALIGN_LEFT); paint.DrawLabel(money, wxRect(wxPoint(middlePoint.x + contentWidth, middlePoint.y - lineHeight * (index+1)), wxSize(contentWidth, contentHeight)), wxALIGN_RIGHT); if (index == 0) { paint.SetBrush(textColor); paint.SetPen(textColor); paint.DrawLine(wxPoint(middlePoint.x, middlePoint.y - (lineHeight-contentHeight)/2), wxPoint(middlePoint.x + width, middlePoint.y- (lineHeight - contentHeight) /2)); } index += 1; } } TickChart::TickChart(wxWindow* parent, wxWindowID id, int timeSpace, TIME_SPACE_TYPE timeSpaceType, wxString xStartTime, wxString xEndTime, const wxPoint& pos, const wxSize& size) : wxControl(parent, id, pos, size, wxBORDER_NONE), timeSpace(timeSpace), timeSpaceType(timeSpaceType), xStartTime(xStartTime), xEndTime(xEndTime), maxYRate(20), limitUpRate(20), preClosePrice(10.00) { SetBackgroundStyle(wxBG_STYLE_PAINT); mousePos = wxPoint(-1, -1); Bind(wxEVT_PAINT, &TickChart::OnPaint, this); Bind(wxEVT_MOTION, &TickChart::OnMouseMove, this); Bind(wxEVT_LEFT_DCLICK, &TickChart::OnDoubleClick, this); mouseDC = new wxClientDC(this); this->xStartTimeSeconds = TickDataUtil::timeStrToSeconds(xStartTime); this->xScopeSeconds = TickDataUtil::tradTimeSub(xEndTime, xStartTime); cout << xStartTime << "==>" << xEndTime << ":" << this->xScopeSeconds << endl; // ³õʼ»¯Êý¾Ý cbCodeInfo = { "","",0 }; underlyingCodeInfo = { "","",0 }; underlyingScale = 1.0f; } void TickChart::OnPaint(wxPaintEvent& event) { try { wxBufferedPaintDC dc(this); PrepareDC(dc); /*wxMemoryDC dc; wxBitmap bitmap(GetSize()); dc.SelectObject(bitmap);*/ dc.SetBackground(wxBrush(*wxBLACK)); // »æÖƱ³¾° dc.SetPen(*wxBLACK); dc.SetBrush(*wxBLACK); dc.DrawRectangle(GetClientRect()); dc.SetTextForeground(*wxBLACK); // »æÖÆ×ø±êÖá dc.SetPen(COLOR_RED); wxRect rect = GetClientRect(); // »æÖÆ×ø±êÖá drawAxis(dc, rect); // »æÖÆÃû³Æ if (cbCodeInfo.codeName.Length() > 0) { dc.SetTextForeground(COLOR_RED_TEXT); wxSize s = dc.GetTextExtent(cbCodeInfo.codeName); dc.DrawText(cbCodeInfo.codeName, wxPoint((rect.GetWidth() - s.GetWidth()) / 2, 0)); } drawTickLine(dc, rect); drawUnderlyingTickLine(dc, rect); // »æÖƳɱ¾Ïß TickData costRateInfo; costRateInfo.rate = costRate; costRateInfo.time = 0; costRateInfo.price = "0.00"; wxPoint startPoint = convertTickDataToPoint(costRateInfo, rect); costRateInfo.time = xScopeSeconds; wxPoint endPoint = convertTickDataToPoint(costRateInfo, rect); wxPen dashedPen(COLOR_YELLOW, 1, wxPENSTYLE_DOT); dc.SetPen(dashedPen); dc.DrawLine(startPoint, endPoint); // »æÖÆÂòÂôµã for (std::list::iterator e = buyPoints.begin(); e != buyPoints.end(); e++) { if (TickDataUtil::tradTimeSub((*e).time, xStartTime) < 0) { continue; } if (TickDataUtil::tradTimeSub((*e).time, xEndTime) > 0) { continue; } TickTradeData info = *e; wxPoint point = convertTickDataToPoint(*e, rect); wxColour color; switch (info.colorType) { case 1: color = wxColor(232, 62, 37); break; case 3: color = wxColor(106, 254, 193); break; default: color = wxColor(232, 62, 37); break; } dc.SetPen(color); dc.SetBrush(color); drawBuyPoint(dc, point); } for (std::list::iterator e = sellPoints.begin(); e != sellPoints.end(); e++) { if (TickDataUtil::tradTimeSub((*e).time, xStartTime) < 0) { continue; } if (TickDataUtil::tradTimeSub((*e).time, xEndTime) > 0) { continue; } wxPoint point = convertTickDataToPoint(*e, rect); drawSellPoint(dc, point); } drawMouse(dc, rect, mousePos); drawBuyAndSellPointInfo(dc, rect, mousePos); drawUnderlyingLatestRate(dc, rect); drawUnderlyingQuotes(dc, rect); //pdc.Clear(); // ²ÉÓÃË«»º´æ»æÖÆ //pdc.Blit(0, 0, GetSize().GetWidth(), GetSize().GetHeight(), &dc, 0, 0); // ¸üнçÃæ Update(); } catch (...) { } } void TickChart::OnMouseMove(wxMouseEvent& event) { event.Skip(); mousePos = event.GetPosition(); Refresh(); } void TickChart::OnDoubleClick(wxMouseEvent& event) { event.Skip(); wxPoint point = event.GetPosition(); if (timeSpaceType != TIME_SPACE_BAR) { return; } int x_time = -1; int line_index = 0;// µÚ¼¸ÌõÏß for (std::list::iterator e = buyPoints.begin(); e != buyPoints.end(); ++e) { TickTradeData tick = *e; wxPoint p = convertTickDataToPoint(tick, GetClientRect()); if (abs(p.x - point.x) < POINT_REDIUS && abs(p.y - point.y) < POINT_REDIUS) { x_time = TickDataUtil::timeStrToSecondsAsAxisX(tick.time, xStartTimeSeconds); line_index = 0; break; } } if (x_time < 0) { for (std::list::iterator e = sellPoints.begin(); e != sellPoints.end(); ++e) { TickTradeData tick = *e; wxPoint p = convertTickDataToPoint(tick, GetClientRect()); if (abs(p.x - point.x) < POINT_REDIUS && abs(p.y - point.y) < POINT_REDIUS) { x_time = TickDataUtil::timeStrToSecondsAsAxisX(tick.time, xStartTimeSeconds); line_index = 0; break; } } } if (x_time < 0) { // ÅжÏË«»÷Êǵã»÷ÔÚÄĸùÏßÉÏ for (std::list::iterator e = underlyingTickDatas.begin(); e != underlyingTickDatas.end(); ++e) { TickData tick = *e; wxPoint p = convertTickDataToPoint(tick, GetClientRect()); if (abs(p.x - point.x) < 4 && abs(p.y - point.y) < 4) { x_time = tick.time; line_index = 1; break; } } } if (x_time < 0) { // ÅжÏË«»÷Êǵã»÷ÔÚÄĸùÏßÉÏ for (std::list::iterator e = cbTickDatas.begin(); e != cbTickDatas.end(); ++e) { TickData tick = *e; wxPoint p = convertTickDataToPoint(tick, GetClientRect()); if (abs(p.x - point.x) < 4) { x_time = tick.time; line_index = 0; break; } } } if (x_time >= 0) { // »ñÈ¡¸½½ü5·ÖÖÓµÄtickÐÅÏ¢ int start_time = x_time - 300; int end_time = x_time + 300; wxString start_time_str = TickDataUtil::axisXSecondsToTimeStr(start_time, xStartTimeSeconds); cout << "tickÏêÇ飺" << start_time_str << endl; if (TickDataUtil::tradTimeSub(start_time_str, "09:30:00") < 0) { start_time_str = "09:30:00"; } wxString end_time_str = TickDataUtil::axisXSecondsToTimeStr(end_time, xStartTimeSeconds); cout << "tickÏêÇ飺" << end_time_str << endl; if (TickDataUtil::tradTimeSub(end_time_str, "15:00:00") > 0) { end_time_str = "15:00:00"; } if (this->tickDetailCallback) { if (line_index == 0) { this->tickDetailCallback(cbCodeInfo, start_time_str, end_time_str, buyPoints, sellPoints, costRate, parentContext); } else if (line_index == 1) { this->tickDetailCallback(underlyingCodeInfo, start_time_str, end_time_str, buyPoints, sellPoints, costRate, parentContext); } } } } void TickChart::Init(CodeBasicInfo cb, CodeBasicInfo underlying, void* parentContext, std::function, std::list, float, void*)> tickCllback) { this->parentContext = parentContext; this->tickDetailCallback = tickCllback; this->cbCodeInfo = cb; this->underlyingCodeInfo = underlying; if (this->cbCodeInfo.code.Length() > 0) { this->preClosePrice = cb.preClosePrice; double limitUpPrice = std::round((cb.preClosePrice * 1.2) * 1000) / 1000; double limitUpRate = std::round(((limitUpPrice - cb.preClosePrice) / cb.preClosePrice) * 10000) / 100; this->maxYRate = limitUpRate; this->maxYRateUnderlying = 0; this->limitUpRate = limitUpRate; } else if (this->underlyingCodeInfo.code.Length() > 0) { float rate = 1.2; if (underlyingCodeInfo.code.find("00") == 0 || underlyingCodeInfo.code.find("60") == 0) { rate = 1.1; } this->preClosePrice = underlyingCodeInfo.preClosePrice; double limitUpPrice = std::round((underlyingCodeInfo.preClosePrice * rate) * 1000) / 1000; double limitUpRate = std::round(((limitUpPrice - underlyingCodeInfo.preClosePrice) / underlyingCodeInfo.preClosePrice) * 10000) / 100; this->maxYRate = limitUpRate; this->maxYRateUnderlying = 0; this->limitUpRate = limitUpRate; } this->cbTickDatas.clear(); this->underlyingTickDatas.clear(); this->buyPoints.clear(); this->sellPoints.clear(); this->costRate = 0; //ÇëÇó֮ǰµÄÊý¾Ý long now = TimeUtil::getNowTimeStamp(); string day = TimeUtil::format(now, "%Y-%m-%d"); string time = TimeUtil::format(now, "%H:%M:%S"); if (TickDataUtil::tradTimeSub(time, xStartTime) >= 0) { if (TickDataUtil::tradTimeSub(time, xEndTime) > 0) { time = xEndTime; } // 09:25Ö®ºó¿ªÊ¼À­Êý¾Ý string startTime = string("").append(day).append(" ").append(xStartTime); string endTime = string("").append(day).append(" ").append(time); if (TickDataUtil::tradTimeSub(startTime, endTime) < this->timeSpace) { if (timeSpaceType == TIME_SPACE_BAR) { if (underlyingCodeInfo.code.Length() > 0) { // À­È¡Õý¹ÉÊý¾Ý DataArray* tempUDatas = JueJinDataUtil::getBarDatas(JueJinDataUtil::getSymbol(underlyingCodeInfo.code.ToStdString()), startTime, endTime); for (int i = 0; i < tempUDatas->count(); i++) { auto datas = tempUDatas->at(i); if (datas.close < 0.0001) { continue; } wxString time_str = TimeUtil::format((long)datas.bob, "%H:%M:%S"); float price = datas.open; AddUnderlyingTickData(time_str, 100 * (price - underlyingCodeInfo.preClosePrice) / underlyingCodeInfo.preClosePrice,std::list(), FALSE); if (i == tempUDatas->count() - 1) { // ¼ÓÔØBarÏßÎÞ·¨¸²¸ÇµÄʱ¼ä¶ÎÊý¾Ý time_str = TimeUtil::format((long)datas.eob, "%H:%M:%S"); wxString tickStartTime = ""; tickStartTime.Append(day).Append(" "); tickStartTime.Append(time_str); DataArray* tempTickDatas = JueJinDataUtil::getTickDatas(JueJinDataUtil::getSymbol(underlyingCodeInfo.code.ToStdString()), tickStartTime.ToStdString(), endTime); for (int j = 0; j < tempTickDatas->count(); j++) { auto datas = tempTickDatas->at(j); if (datas.price < 0.0001) { continue; } std::list quotes; for (int n = 0; n < 5; n++) { quotes.push_back(datas.quotes[n]); } AddUnderlyingTickData(TimeUtil::format((long)datas.created_at, "%H:%M:%S"), 100 * (datas.price - underlyingCodeInfo.preClosePrice) / underlyingCodeInfo.preClosePrice, quotes, FALSE); } } } Tick tick = JueJinDataUtil::currentTick(JueJinDataUtil::getSymbol(underlyingCodeInfo.code.ToStdString())); std::list quotes; for (int n = 0; n < 5; n++) { quotes.push_back(tick.quotes[n]); } AddUnderlyingTickData(TimeUtil::format((long)tick.created_at, "%H:%M:%S"), 100 * (tick.price - underlyingCodeInfo.preClosePrice) / underlyingCodeInfo.preClosePrice, quotes, FALSE); } if (cbCodeInfo.code.Length() > 0) { //ÐèÒª´óÓÚtimeSpace²ÅÄÜÀ­Êý¾Ý DataArray* tempDatas = JueJinDataUtil::getBarDatas(JueJinDataUtil::getSymbol(cbCodeInfo.code.ToStdString()), startTime, endTime); for (int i = 0; i < tempDatas->count(); i++) { auto datas = tempDatas->at(i); if (datas.close < 0.0001) { continue; } string time_str = TimeUtil::format((long)datas.bob, "%H:%M:%S"); float price = datas.open; AddTickData(time_str, 100 * (price - preClosePrice) / preClosePrice, to_string(datas.close), FALSE); if (i == tempDatas->count() - 1) { // ¼ÓÔØBarÏßÎÞ·¨¸²¸ÇµÄʱ¼ä¶ÎÊý¾Ý time_str = TimeUtil::format((long)datas.eob, "%H:%M:%S"); price = datas.close; wxString tickStartTime = ""; tickStartTime.Append(day).Append(" "); tickStartTime.Append(time_str); DataArray* tempTickDatas = JueJinDataUtil::getTickDatas(JueJinDataUtil::getSymbol(cbCodeInfo.code.ToStdString()), tickStartTime.ToStdString(), endTime); for (int j = 0; j < tempTickDatas->count(); j++) { auto datas = tempTickDatas->at(j); if (datas.price < 0.0001) { continue; } AddTickData(TimeUtil::format((long)datas.created_at, "%H:%M:%S"), 100 * (datas.price - preClosePrice) / preClosePrice, to_string(datas.price), FALSE); } } } } } else if (timeSpaceType == TIME_SPACE_TICK) { if (cbCodeInfo.code.Length() > 0) { //ÐèÒª´óÓÚtimeSpace²ÅÄÜÀ­Êý¾Ý DataArray* tempDatas = JueJinDataUtil::getTickDatas(JueJinDataUtil::getSymbol(cbCodeInfo.code.ToStdString()), startTime, endTime); for (int i = 0; i < tempDatas->count(); i++) { auto datas = tempDatas->at(i); if (datas.price < 0.0001) { continue; } AddTickData(TimeUtil::format((long)datas.created_at, "%H:%M:%S"), 100 * (datas.price - preClosePrice) / preClosePrice, to_string(datas.price), FALSE); } } if (underlyingCodeInfo.code.Length() > 0) { // À­È¡Õý¹ÉÊý¾Ý DataArray* tempUDatas = JueJinDataUtil::getTickDatas(JueJinDataUtil::getSymbol(underlyingCodeInfo.code.ToStdString()), startTime, endTime); for (int i = 0; i < tempUDatas->count(); i++) { auto datas = tempUDatas->at(i); if (datas.price < 0.0001) { continue; } AddUnderlyingTickData(TimeUtil::format((long)datas.created_at, "%H:%M:%S"), 100 * (datas.price - underlyingCodeInfo.preClosePrice) / underlyingCodeInfo.preClosePrice, std::list(), FALSE); } } } } } Refresh(); } void TickChart::AddTickData(wxString time, float rate, wxString price, bool refresh) { if (TickDataUtil::tradTimeSub(time, xEndTime) > 0) { return; } int seconds = TickDataUtil::timeStrToSecondsAsAxisX(time, TickDataUtil::timeStrToSeconds(xStartTime)); if (!cbTickDatas.empty()) { TickData last = cbTickDatas.back(); if (last.time > seconds) { return; } if (seconds / this->timeSpace != last.time / this->timeSpace) { cbTickDatas.push_back(TickData({ seconds , rate, price })); } else { cbTickDatas.back().price = price; cbTickDatas.back().time = seconds; cbTickDatas.back().rate = rate; cout << "×îºóÒ»ÌõÊý¾Ý£º" << cbTickDatas.back().time << "-" << cbTickDatas.back().price << endl; } float newMaxYRate = abs(rate) + MAX_RATE_FLOAT; if (newMaxYRate > maxYRate) { maxYRate = min(newMaxYRate, limitUpRate); if (maxYRateUnderlying > 0) { underlyingScale = maxYRate / maxYRateUnderlying / 2; } } } else { cbTickDatas.push_back(TickData({ seconds , rate, price })); if (abs(rate) < limitUpRate - MAX_RATE_FLOAT) { maxYRate = abs(rate) + MAX_RATE_FLOAT; if (maxYRateUnderlying > 0) { underlyingScale = maxYRate / maxYRateUnderlying / 2; } } } if (refresh) { Refresh(); } } void TickChart::AddUnderlyingTickData(wxString time, float rate, list quotes, bool refresh) { if (TickDataUtil::tradTimeSub(time, xEndTime) > 120) { return; } int seconds = TickDataUtil::timeStrToSecondsAsAxisX(time, xStartTimeSeconds); if (!underlyingTickDatas.empty()) { TickData last = underlyingTickDatas.back(); if (last.time > seconds) { return; } if (seconds / this->timeSpace != last.time / this->timeSpace) { underlyingTickDatas.push_back(TickData({ seconds , rate, "", quotes })); } else { underlyingTickDatas.back().price = ""; underlyingTickDatas.back().time = seconds; underlyingTickDatas.back().rate = rate; underlyingTickDatas.back().quotes = quotes; cout << "×îºóÒ»ÌõÊý¾Ý£º" << underlyingTickDatas.back().time << "-" << underlyingTickDatas.back().price << endl; } float newMaxYRate = abs(rate) + MAX_RATE_FLOAT; if (newMaxYRate > maxYRateUnderlying) { maxYRateUnderlying = min(newMaxYRate, limitUpRate); } } else { underlyingTickDatas.push_back(TickData({ seconds , rate, "", quotes })); } // Õý¹É²»¸¡¶¯ float newMaxYRate = abs(rate); if (newMaxYRate > maxYRateUnderlying) { maxYRateUnderlying = min(newMaxYRate, limitUpRate); } if (refresh) { Refresh(); } } void TickChart::AddBuyPoint(wxString time, float rate, wxString price, int volume, wxString money, int type) { AddBuyPoint(TickTradeData({ time , rate, price,volume, money, type })); } void TickChart::AddBuyPoint(TickTradeData data) { buyPoints.push_back(data); Refresh(); } void TickChart::SetBuyPoint(std::list datas) { buyPoints.clear(); for (std::list::iterator e = datas.begin(); e != datas.end(); ++e) { buyPoints.push_back(*e); } } void TickChart::AddSellPoint(wxString time, float rate, wxString price, int volume, wxString money) { AddSellPoint(TickTradeData({ time , rate, price ,volume, money })); } void TickChart::AddSellPoint(TickTradeData data) { sellPoints.push_back(data); Refresh(); } void TickChart::SetSellPoint(std::list datas) { sellPoints.clear(); for (std::list::iterator e = datas.begin(); e != datas.end(); ++e) { sellPoints.push_back(*e); } } void TickChart::SetCostRate(wxString code, float rate, wxString price) { this->costRate = rate; if (this->costRate > limitUpRate) { this->costRate = limitUpRate; } Refresh(); }