策略为王源代码分析-GraphView.cpp-显示K线图

Published

数据调用链:硬盘数据---KDATA---CKData---CStock---CStockGraph---CGraphView。

StockGraph.cpp是专门负责画K线图的类;包含数据加载,键盘,鼠标定义等功能。

GraphView.cpp是负责画日K线、其他周期K线的类

 

function index of table

\src\Client\StkUI\View\StockGraph.cpp
//画周期K线的左上角信息 by freeman
void CStockGraph::DrawKData(CDC* pDC, CRect rect)

//画窗口右上角的参数窗口 by freeman
void CStockGraph::DrawReportParam(CDC* pDC)

第一部分 视图的结构和数据初始化

step 1. 初始化视图结构

当视图切换到GraphView时,首先调用ONCREATE()对view进行初始化,主要是准备窗口右下角的标签项(如火焰山等)、注册窗口句柄。

//准备窗口右下角的标签项,如火焰山等;注册窗口句柄 by freeman
int CGraphView::OnCreate(LPCREATESTRUCT lpCreateStruct) 
{
	if (CView::OnCreate(lpCreateStruct) == -1)
		return -1;
	
	CFont font;
	if (!font.CreateStockObject(DEFAULT_GUI_FONT))
		font.CreateStockObject(ANSI_VAR_FONT);
	SetFont(&font);

	m_graph.SetParent(this);

	// tab
	//if (!m_wndReportTab.Create(WS_VISIBLE|WS_CHILD,CRect(0,0,180,19),this,IDC_GRAPHVIEW_REPORTTAB))
	//	return -1;
	//准备窗口右下角的标签项,如火焰山等 by freeman
	CTSKTabManagerItem* pItem;
	CString	strName;

	strName.LoadString(IDS_GRAPHTAB_PARAM);
	pItem = new CTSKTabManagerItem();
	pItem->SetCaption(strName);
	AddItem(GV_REPORTTAB_PARAM, pItem);

	strName.LoadString(IDS_GRAPHTAB_COST);
	pItem = new CTSKTabManagerItem();
	pItem->SetCaption(strName);
	AddItem(GV_REPORTTAB_COST, pItem);

	strName.LoadString(IDS_GRAPHTAB_FLAME);
	pItem = new CTSKTabManagerItem();
	pItem->SetCaption(strName);
	AddItem(GV_REPORTTAB_FLAME, pItem);

	strName.LoadString(IDS_GRAPHTAB_ACTIVITY);
	pItem = new CTSKTabManagerItem();
	pItem->SetCaption(strName);
	AddItem(GV_REPORTTAB_ACTIVITY, pItem);

	SetSelectedItem(GetItem(0));

	m_nMinWidth = 40;

	//m_wndReportTab.SetColorTabs(AfxGetProfile().GetColor(CColorClass::clrGraphBK));
	//m_wndReportTab.SetSelectTabColor(AfxGetProfile().GetColor(CColorClass::clrGraphBK),
	//								AfxGetProfile().GetColor(CColorClass::clrTitle));
	//m_wndReportTab.SetAutoAjust(FALSE);
	//m_wndReportTab.ShowButtonClose(FALSE);
	//m_wndReportTab.SetALingTabs(CGuiTabWnd::ALN_BOTTOM);

	// 实时行情刷新,注册窗口句柄
	AfxGetStkReceiver().AddRcvDataWnd(GetSafeHwnd());

	return 0;
}

step 2:初始化视图数据

系统调用OnInitialUpDate()初始化数据。

在OnInitialUpdate() 函数中,

step 1.首先用AfxGetProfile().GetCurrentStock(&info)从全局变量中获取当前股票信息。

step 2.然后初始化用m_graph.SetCurStock(info)设置StockGraph类的当前股票。

step 3.接着调用m_graph.PrepareStockData(),m_graph会根据当前股票代码加载K线数据。

step 4.调用Invalidate()后,系统会发送WM_PAINT消息。由OnPaint消息处理函数来响应。

OnPaint是WM_PAINT消息的消息处理函数,在OnPaint中调用OnDraw。

// 初始化,准备数据
void CGraphView::OnInitialUpdate() 
{
	CView::OnInitialUpdate();
	
	// TODO: Add your specialized code here and/or call the base class
	OnUpdate(NULL, UPDATE_HINT_GRAPHVIEW, NULL);
}

void CGraphView::OnUpdate(CView* pSender, LPARAM lHint, CObject* pHint) 
{
	// TODO: Add your specialized code here and/or call the base class
	if (UPDATE_HINT_GRAPHVIEW != lHint && UPDATE_HINT_GRAPHVIEW_NOTRELOADDATA != lHint)
		return;
	if (!IsWindowVisible())
		return;
	SetFocus();

	CStockInfo	info;
	//从配置文件中取出当前股票 by freeman
	if (AfxGetProfile().GetCurrentStock(&info))
	{
		//CStockGraph	m_graph;设置当前股票信息
		m_graph.SetCurStock(info);
		//加载相关数据 ,包括加载K线数据,计算指标等  by freeman
		m_graph.PrepareStockData(UPDATE_HINT_GRAPHVIEW_NOTRELOADDATA != lHint);
	}
	else
	{
		m_graph.SetCurStock(STKLIB_CODE_MAIN);
		m_graph.PrepareStockData(UPDATE_HINT_GRAPHVIEW_NOTRELOADDATA != lHint);
		AfxGetProfile().SetCurrentStock(STKLIB_CODE_MAIN, FALSE);
	}

	Invalidate();

	CMainFrame	* pFrame = AfxGetMainFrame();
	if (pFrame)
		pFrame->m_SearchBox.SetCurrentWindowText();
}

CStockGraph类根据当前股票代码加载K线数据、技术指标数据。

//CStockGraph::PrepareStockData( BOOL bReload )加载画图所需要的数据 by freeman
BOOL CStockGraph::PrepareStockData(BOOL bReload)
{
	if (!m_CurStock.GetStockInfo().IsValidStock())
		return FALSE;

	CStockInfo	info;
	if (AfxGetStockContainer().GetStockInfo(m_CurStock.GetStockCode(), &info)
		&& m_CurStock.GetStockInfo().IsEqualTo(info.GetMarket(), info.GetStockCode()))
	{
		m_CurStock.SetStockInfo(&info);
		m_CurStockDown.SetStockInfo(&info);
	}

	int nOldSize = m_CurStock.GetKData(m_nCurKType).GetSize();

	// Prepare Data
	AfxPrepareStockData(&AfxGetDB(), m_CurStock, m_nCurKType, m_nCurKFormat, m_nCurMaindataType, FALSE, bReload);
	AfxPrepareStockData(&AfxGetDB(), m_CurStockDown, m_nCurKType, CKData::formatXDRdown, m_nCurMaindataType, FALSE, bReload);

	if (m_CurStock.GetKData(m_nCurKType).GetSize() != nOldSize)
		ResetIndex();

	AfxGetStkReceiver().RequestKData(&m_CurStock, m_nCurKType);

	m_techparam.Clear();
	m_techparam.SetKData(&(m_CurStockDown.GetKData(m_nCurKType)));
	m_techparam.volume.SetKData(&(m_CurStock.GetKData(m_nCurKType)));
	m_techparam.ma.SetKData(&(m_CurStock.GetKData(m_nCurKType)));
	m_techparam.bbi.SetKData(&(m_CurStock.GetKData(m_nCurKType)));
	m_techparam.boll.SetKData(&(m_CurStock.GetKData(m_nCurKType)));
	m_techparam.pv.SetKData(&(m_CurStock.GetKData(m_nCurKType)));
	m_techparam.sar.SetKData(&(m_CurStock.GetKData(m_nCurKType)));
	m_techparam.dj.SetKData(&(m_CurStock.GetKData(m_nCurKType)));
	m_techparam.mike.SetKData(&(m_CurStock.GetKData(m_nCurKType)));

	m_techparam.dj2.SetKData(&(m_CurStock.GetKData(m_nCurKType)));

	return TRUE;
}

ONCREATE只是产生VIEW的基本结构和变量而在OnInitialUpDate()中,主要初始化视图中控件等,对各个变量进行初始化操作。OnCreate()是生成结构的,而OnInitialUpDate是对结构进行初始化。两个一个相当于硬件一个相当于软件,功能和作用完全不同。

step 3:发送WM_PAINT消息

数据初始化完成后,调用Invalidate(),系统发送WM_PAINT消息。OnPaint是WM_PAINT消息的消息处理函数,在OnPaint中调用OnDraw()处理。

第二部分 画日K线图

MFC是事件消息响应机制,根据不同的消息,由不同的函数进行处理。

step 4:画K线图

收到WM_PAINT消息后,由画图函数OnDraw()调用了m_graph.Redraw()进行绘图。

 

G:\stock\TskingVS2019\src\Client\StkUI\View\GraphView.cpp

/////////////////////////////////////////////////////////////////////////////
// CGraphView drawing
//说明:OnPaint是WM_PAINT消息的消息处理函数,在OnPaint中调用OnDraw。
//OnPaint()是CWnd的类成员,负责响应WM_PAINT消息。OnDraw()是CVIEW的成员函数,没有响应消息的功能.当视图变得无效时(包括大小的改变,移动,被遮盖等等),Windows发送WM_PAINT消息。该视图的OnPaint 处理函数通过创建CPaintDC类的DC对象来响应该消息并调用视图的OnDraw成员函数.OnPaint最后也要调用OnDraw,因此一般在OnDraw函数中进行绘制。

void CGraphView::OnDraw(CDC* pDC)
{
	CStaticDoc* pDoc = GetDocument();
	ASSERT_VALID(pDoc);

	CRect rectClient;
	GetClientRect(&rectClient);

	CMemDC memDC(pDC);
	m_graph.Redraw(&memDC, rectClient); //画图

G:\stock\TskingVS2019\src\Client\StkUI\View\StockGraph.cpp

void CStockGraph::Redraw(CDC* pDC, CRect rectAll)
{
	ASSERT(m_pParent && ::IsWindow(m_pParent->GetSafeHwnd()));
	if (m_rectAll != rectAll)
		ResetClient(rectAll);
	DrawStock(pDC);
}

CStockGraph中的绘图函数为DrawStock,在这个成员函数里分别调用下面的几个函数画出各个子窗口:

图中1为KDATA,为股票的数据信息,是CStockGraph::DrawKData( )调用画出来的。

图中2为KLINE,为股票的K线图,是CStockGraph::DrawKLine( )调用画出来的。

图中3为TechLine,为技术指标线,是CStockGraph::DrawTechLine( pDC )调用画出来的。

图中3区域的下面为时间轴,是调用CStockGraph::DrawDateAxis( pDC )画出来的

图中4区域为Report信息区域,是调用CStockGraph::DrawReportRegion( pDC )画出来的。

//画股票K线 by freeman
void CStockGraph::DrawStock(CDC* pDC)
{
	ASSERT(m_pParent && ::IsWindow(m_pParent->GetSafeHwnd()));
	if (!m_pParent || !::IsWindow(m_pParent->GetSafeHwnd()))
		return;

	CClientDC	dc(m_pParent);
	if (NULL == pDC)
		pDC = &dc;

	if (!m_CurStock.GetStockInfo().IsValidStock())
		return;

	CKData& kdata = m_CurStock.GetKData(m_nCurKType);
	if (kdata.GetSize() == 0)
	{
		DrawNoDataInfo(pDC); //股票K线没有数据时,显示获取更多数据请点击菜单“数据->历史数据下载...”。"
	}
	else if (PrepareDrawKLine()) // Reset m_nIndexStart, m_nIndexEnd, m_nIndexCurrent
	{
		DrawDateAxis(pDC); //画K线底部的日期提示框里的文字
		DrawTechLine(pDC); //画窗口底部的技术指标线
		DrawKLine(pDC); //画K线图
		DrawKData(); //画周期K线的左上角信息
	}

	DrawReportRegion(pDC); //画日K线右下角窗口:参数、成本、火焰山、活跃
}
//画周期K线的左上角信息 by freeman
void CStockGraph::DrawKData(CDC* pDC, CRect rect)
{

 

//画周期K线图 by freeman
void CStockGraph::DrawKLine(CDC* pDC)

 

//画单根K线 by freeman
void CStockGraph::DrawOneKLine(CDC* pDC, int nIndexPos, int nIndexKD, CKData* pKData, double dMin, double dMax, BOOL bGreyed)

 

/画窗口右上角的参数窗口 by freeman
void CStockGraph::DrawReportParam(CDC* pDC)

 

画技术指标的函数

//画周期K线叠加技术指标 如boll线、叠加图等 by freeman
void CStockGraph::DrawKLineAttribute(CDC* pDC, UINT nTech, CRect rect, BOOL bDrawTitle, double dMin, double dMax)
//画窗口底部的技术指标线 by freeman
void CStockGraph::DrawTechLine(CDC* pDC, UINT nTech, CRect rect, BOOL bDrawTitle)

step 1:在各个界面,被选中的股票会存入存入AfxGetProfile().GetCurrentStock(&info)变量

step 2:切换到K线图时,初始化部分会先从配置文件中取出当前股票信息,然后初始化m_graph变量。m_graph是一个StockGraph类。

G:\stock\TskingVS2019\src\Client\StkUI\View\GraphView.cpp

AfxGetProfile().GetCurrentStock(&info)

 

BOOL CGraphView::PreCreateWindow(CREATESTRUCT& cs)
{
	// TODO: Modify the Window class or styles here by modifying
	//  the CREATESTRUCT cs

	return CView::PreCreateWindow(cs);
}

void CGraphView::OnInitialUpdate() 
{
	CView::OnInitialUpdate();
	
	// TODO: Add your specialized code here and/or call the base class
	OnUpdate(NULL, UPDATE_HINT_GRAPHVIEW, NULL);
}

void CGraphView::OnUpdate(CView* pSender, LPARAM lHint, CObject* pHint) 
{
	// TODO: Add your specialized code here and/or call the base class
	if (UPDATE_HINT_GRAPHVIEW != lHint && UPDATE_HINT_GRAPHVIEW_NOTRELOADDATA != lHint)
		return;
	if (!IsWindowVisible())
		return;
	SetFocus();

	CStockInfo	info;
	if (AfxGetProfile().GetCurrentStock(&info))
	{
		m_graph.SetCurStock(info);
		m_graph.PrepareStockData(UPDATE_HINT_GRAPHVIEW_NOTRELOADDATA != lHint);
	}
	else
	{
		m_graph.SetCurStock(STKLIB_CODE_MAIN);
		m_graph.PrepareStockData(UPDATE_HINT_GRAPHVIEW_NOTRELOADDATA != lHint);
		AfxGetProfile().SetCurrentStock(STKLIB_CODE_MAIN, FALSE);
	}

	Invalidate();

	CMainFrame	* pFrame = AfxGetMainFrame();
	if (pFrame)
		pFrame->m_SearchBox.SetCurrentWindowText();
}

窗口右下角的标签项

准备窗口右下角的标签项,如火焰山等

/准备窗口右下角的标签项,如火焰山等;注册窗口句柄 by freeman
int CGraphView::OnCreate(LPCREATESTRUCT lpCreateStruct) 
{
	if (CView::OnCreate(lpCreateStruct) == -1)
		return -1;
	
	CFont font;
	if (!font.CreateStockObject(DEFAULT_GUI_FONT))
		font.CreateStockObject(ANSI_VAR_FONT);
	SetFont(&font);

	m_graph.SetParent(this);

	// tab
	//if (!m_wndReportTab.Create(WS_VISIBLE|WS_CHILD,CRect(0,0,180,19),this,IDC_GRAPHVIEW_REPORTTAB))
	//	return -1;
	//准备窗口右下角的标签项,如火焰山等 by freeman
	CTSKTabManagerItem* pItem;
	CString	strName;

	strName.LoadString(IDS_GRAPHTAB_PARAM);
	pItem = new CTSKTabManagerItem();
	pItem->SetCaption(strName);
	AddItem(GV_REPORTTAB_PARAM, pItem);

	strName.LoadString(IDS_GRAPHTAB_COST);
	pItem = new CTSKTabManagerItem();
	pItem->SetCaption(strName);
	AddItem(GV_REPORTTAB_COST, pItem);

	strName.LoadString(IDS_GRAPHTAB_FLAME);
	pItem = new CTSKTabManagerItem();
	pItem->SetCaption(strName);
	AddItem(GV_REPORTTAB_FLAME, pItem);

	strName.LoadString(IDS_GRAPHTAB_ACTIVITY);
	pItem = new CTSKTabManagerItem();
	pItem->SetCaption(strName);
	AddItem(GV_REPORTTAB_ACTIVITY, pItem);

	SetSelectedItem(GetItem(0));

	m_nMinWidth = 40;

	//m_wndReportTab.SetColorTabs(AfxGetProfile().GetColor(CColorClass::clrGraphBK));
	//m_wndReportTab.SetSelectTabColor(AfxGetProfile().GetColor(CColorClass::clrGraphBK),
	//								AfxGetProfile().GetColor(CColorClass::clrTitle));
	//m_wndReportTab.SetAutoAjust(FALSE);
	//m_wndReportTab.ShowButtonClose(FALSE);
	//m_wndReportTab.SetALingTabs(CGuiTabWnd::ALN_BOTTOM);

	// 实时行情刷新,注册窗口句柄
	AfxGetStkReceiver().AddRcvDataWnd(GetSafeHwnd());

	return 0;
}

窗口右上角的窗口显示内容-标签项-参数

显示的字符串定义

StkUI\StkUI.rc

STRINGTABLE 
BEGIN
    IDS_STOCKGRAPH_OPEN     "开    盘"
    IDS_STOCKGRAPH_HIGH     "最    高"
    IDS_STOCKGRAPH_LOW      "最    低"
    IDS_STOCKGRAPH_CLOSE    "收    盘"
    IDS_STOCKGRAPH_VOLUME   "成 交 量"
    IDS_STOCKGRAPH_AMOUNT   "成 交 额"
    IDS_STOCKGRAPH_YIELDAVERAGE "年收益率"
    IDS_STOCKGRAPH_DAY      "日"
    IDS_STOCKGRAPH_YIELDSTDDEV "标准差"
    IDS_STOCKGRAPH_BEITE    "β值"
    IDS_STOCKGRAPH_XIAPU    "夏普指数"
    IDS_STOCKGRAPH_CHANGEHAND "换手"
    IDS_STOCKGRAPH_RATIOVOLUME "量比"
    //IDS_STOCKGRAPH_SHARECURRENCY "流通股本-万"
	IDS_STOCKGRAPH_SHARECURRENCY "流通股本"  //changed by freeman
    IDS_STOCKGRAPH_NETASSETPS "每股净资产"
    IDS_STOCKGRAPH_EPS      "每股收益"
END
STRINGTABLE
BEGIN
    IDS_STOCKGRAPH_RS       "相对强度"
    IDS_STOCKGRAPH_TIME2    "时间"
    IDS_STOCKGRAPH_PRICEAVERAGE "成交均价"
    IDS_STOCKGRAPH_RELATIVECHANGEHAND "相对换手率"
    IDS_GRAPHTAB_PARAM      "参数"
    IDS_GRAPHTAB_COST       "成本"
    IDS_STOCKGRAPH_SHARETOTAL "总股本-万"
    IDS_TITLE_INFOVIEW      "在线资讯"
    IDS_SETPARAM_INVALID    "您设定的参数不正确,请重新设定。"
    IDS_TITLE_GROUPVIEW     "分组"
    IDS_TITLE_TECHSVIEW     "指标"
    IDS_GROUPVIEW_GROUP     "分组"
    IDS_GROUPVIEW_DOMAIN    "板块"
    IDS_STRATEGY_SETPRPT    "请设定新策略的名称和一些属性。"
    IDS_PROPERTYSHEET_NEXT  "下一步(&N) >"
    IDS_STOCKGRAPH_NOKDATA  "。获取更多数据请点击菜单“数据->历史数据下载...”。"
END
STRINGTABLE
BEGIN
    IDS_EXPORTDEST_CONFIRMCLOSE "正在导出,您确定要中断导出,关闭对话框吗?"
    IDS_SETDRDATA_DATE      "日期"
    IDS_SETDRDATA_BONUS     "10派X元"
    IDS_SETDRDATA_BONUSSHARE "10送X股"
    IDS_SETDRDATA_RATIONSHARE "10配X股"
    IDS_SETDRDATA_RATIONVALUE "配股价"
    IDS_SETDRDATA_NOSTOCK   "请在左边选择您要修改的股票。"
    IDS_SETCOLUMN_SAMEASYIELDAVERAGE "与年平均收益率相同"
    IDS_SETCOLUMN_IFRECALCULATE 
                            "计算年平均收益率天数已经改变,现在重新计算平均收益率、β值并保存吗?否则股票列表中显示的数据还是以前的。\n您可以通过菜单 “数据-〉重新计算平均收益率” 执行该操作。"
    IDS_INSTALLPAC_IFRECALCULATE 
                            "数据已经更新,现在重新计算年平均收益率、β值并保存吗?否则股票列表中显示的数据还是以前的。\n您可以通过菜单 “数据-〉重新计算平均收益率” 执行该操作。"
    IDS_STOCKGRAPH_KLINE    "K     线"
    IDS_STOCKGRAPH_FONTNAME "楷体"
    IDS_STOCKGRAPH_TIME     "时    间"
END

和日K线有关的ID定义

#define IDS_STOCKGRAPH_KLINE            45773
#define IDS_STOCKGRAPH_FONTNAME         45774
#define IDS_STOCKGRAPH_TIME             45775
#define IDS_STOCKGRAPH_OPEN             45776
#define IDS_STOCKGRAPH_HIGH             45777
#define IDS_STOCKGRAPH_LOW              45778
#define IDS_STOCKGRAPH_CLOSE            45779
#define IDS_STOCKGRAPH_VOLUME           45780
#define IDS_STOCKGRAPH_AMOUNT           45781
#define IDS_STOCKGRAPH_YIELDAVERAGE     45782
#define IDS_STOCKGRAPH_DAY              45783
#define IDS_STOCKGRAPH_YIELDSTDDEV      45784
#define IDS_STOCKGRAPH_BEITE            45785
#define IDS_STOCKGRAPH_XIAPU            45786
#define IDS_STOCKGRAPH_CHANGEHAND       45787
#define IDS_STOCKGRAPH_RATIOVOLUME      45788
#define IDS_STOCKGRAPH_SHARECURRENCY    45789
#define IDS_STOCKGRAPH_NETASSETPS       45790
#define IDS_STOCKGRAPH_EPS              45791
#define IDS_STOCKGRAPH_RS               45792
#define IDS_STOCKGRAPH_TIME2            45793
#define IDS_STOCKGRAPH_PRICEAVERAGE     45794
#define IDS_STOCKGRAPH_RELATIVECHANGEHAND 45795
#define IDS_STOCKGRAPH_SHARETOTAL       45798
#define IDS_STOCKGRAPH_NOKDATA          45807
#define IDS_STOCKGRAPH_PROJECT          45808
#define IDS_STOCKGRAPH_PRIMARY          45809
#define IDS_STOCKGRAPH_MEDIATE          45810
#define IDS_STOCKGRAPH_MIGHT            45811
#define IDS_STOCKGRAPH_PRESSURE         45812
#define IDS_STOCKGRAPH_UPHOLD           45813
#define IDS_STOCKGRAPH_RECENTCWDISFMT   45829
#define IDS_STOCKGRAPH_PASTCWDISFMT     45830
#define IDS_STOCKGRAPH_GAINPERCENT      45831
#define IDS_STOCKGRAPH_COSTAVE          45832
#define IDS_STOCKGRAPH_MASSFMT90        45833
#define IDS_STOCKGRAPH_MASSFMT70        45834
#define IDS_STOCKGRAPH_PE               45842

 

第三部分 事件消息响应

3.1 按键F5的消息响应

G:\stock\TskingVS2019\src\Client\StkUI\View\GraphView.cpp

//处理按键,按F5 切换到 分时线图 by freeman
BOOL CGraphView::PreTranslateMessage(MSG* pMsg) 
{
	if (WM_KEYDOWN == pMsg->message)
	{
		switch(pMsg->wParam)
		{
		case VK_F5:  //K线图 F5热键、快捷键定义   by freeman
			{
				AfxSwitchToStaticView(RUNTIME_CLASS(CRealTimeView));
				CRealTimeView * pView = AfxGetRealTimeView();
				if (pView)
					pView->ChangeDrawMode(CRealTime::modePriceLine);
			}
			return TRUE;
		
		}
		
	}
	
	return CView::PreTranslateMessage(pMsg);
}

 

3.2 按键回车键的消息响应

void CGraphView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) 
{
	switch(nChar)
	{
	case VK_RETURN:
		m_graph.OnReturn(IsSHIFTpressed(), IsCTRLpressed());
		break;
        .....
}

 

第四部分 画K线实现原理

//画周期K线图 by freeman
void CStockGraph::DrawKLine(CDC* pDC)
{

// Draw K Line 循环画K线
	for (int k = m_nIndexStart; k <= m_nIndexEnd; k++)
	{
		DrawOneKLine(pDC, k, k, &kdata, dMin, dMax, FALSE);
	}

}

 

//画单根K线 by freeman
void CStockGraph::DrawOneKLine(CDC* pDC, int nIndexPos, int nIndexKD, CKData* pKData, double dMin, double dMax, BOOL bGreyed)
{

if (CStockGraph::klineCandle == m_nCurKLineMode) //蜡烛线 系统缺省为蜡烛线
	{
		// Draw Entity
		COLORREF	clr = clrRise;
		if (kd.m_fClose < kd.m_fOpen)
			clr = clrFallEntity;
		if (kd.m_date > m_dwLatestDate)
			clr = clrNewKLine;
		if (bGreyed)
			clr = clrDJ;
		pDC->SetBkColor(clrBK);
		if (kd.m_fClose < kd.m_fOpen)
			pDC->FillSolidRect(&rcEntity, clr); //画阴线实体
		else
			pDC->Draw3dRect(&rcEntity, clr, clr); //画阳线实体

		// Draw Line
		//画K线上的最高和最低价格的线
		CPen	pen(PS_SOLID, 1, clr);
		CPen* pOldPen = pDC->SelectObject(&pen);
		pDC->MoveTo(xMedium, yHigh);
		pDC->LineTo(xMedium, rcEntity.top);  //最高价画到实体顶部
		pDC->MoveTo(xMedium, rcEntity.bottom);
		pDC->LineTo(xMedium, yLow);   //实体底部画到最低价

		


		pDC->SelectObject(pOldPen);
	}

}

MFC中无标题栏窗口的移动

https://www.cnblogs.com/huhu0013/p/4640728.html