策略为王源代码分析-RealTimeView.cpp-显示分时图

Published

摘要:

1.分时图由RealTimeView.cpp和RealTime.cpp两个类完成。其中:

RealTimeView.cpp负责对画框、画右下角标签。捕获键盘事件后调用CRealTime类中的函数进行处理。

RealTime.cpp负责对数据进行处理,处理完成后,对CRealTimeView传过来的参数PDC进行画图,然后反过来调用显示实时行情。

2.分为多股同列和单个股票两种情形。

 

3.函数功能索引


├── src                                         // 源码目录
│   ├── CRealTime::DrawReportRegion(CDC* pDC)                              // 组件
│   │   ├── CRealTime::DrawReportRegion(CDC* pDC)                              // 右下角标签画图
│   │   │   ├── DrawReportQuote(pDC);			//笔
│   │   │   ├── DrawReportPrice(pDC);			       //价
│   │   │   ├── computeTime.vue                 // 倒计时组件
│   │   │   ├── loading.vue                     // 页面初始化加载数据的动画组件
│   │   │   ├── mixin.js                        // 组件混合(包括:指令-下拉加载更多,处理图片地址)
│   │   │   ├── ratingStar.vue                  // 评论的五颗星组件
│   │   │   └── shoplist.vue                    // msite和shop页面的餐馆列表公共组件
│   │   ├── footer
│   │   │   └── footGuide.vue                   // 底部公共组件
│   │   └── header
│   │       └── head.vue                        // 头部公共组件
│   ├── config                                  // 基本配置
│   │   ├── env.js                              // 环境切换配置
│   │   ├── fetch.js                            // 获取数据
│   │   ├── mUtils.js                           // 常用的js方法
│   │   └── rem.js                              // px转换rem
│   ├── images                                  // 公共图片
│   ├── page
│   │   ├── balance
│   │   │   ├── balance.vue                     // 余额页
│   │   │   └── children
│   │   │       └── detail.vue                  // 余额说明
│   │   ├── benefit
│   │   │   ├── benefit.vue                     // 红包页
│   │   │   └── children
│   │   │       ├── commend.vue                 // 推荐有奖
│   │   │       ├── coupon.vue                  // 代金券说明
│   │   │       ├── exchange.vue                // 兑换红包
│   │   │       ├── hbDescription.vue           // 红包说明
│   │   │       └── hbHistory.vue               // 历史红包
│   │   ├── city                 
│   │   │   └── city.vue                        // 当前城市页
│   │   ├── confirmOrder
│   │   │   ├── children
│   │   │   │   ├── children
│   │   │   │   │   ├── addAddress.vue          // 添加地址页
│   │   │   │   │   └── children
│   │   │   │   │       └── searchAddress.vue   // 搜索地址页
│   │   │   │   ├── chooseAddress.vue           // 选择地址页
│   │   │   │   ├── invoice.vue                 // 选择发票页
│   │   │   │   ├── payment.vue                 // 付款页
│   │   │   │   ├── remark.vue                  // 订单备注页 
│   │   │   │   └── userValidation.vue          // 用户验证页
│   │   │   └── confirmOrder.vue                // 确认订单页
│   │   ├── download
│   │   │   └── download.vue                    // 下载App
│   │   ├── find
│   │   │   └── find.vue                        // 发现页
│   │   ├── food
│   │   │   └── food.vue                        // 食品筛选排序页
│   │   ├── forget
│   │   │   └── forget.vue                      // 忘记密码,修改密码页
│   │   ├── home
│   │   │   └── home.vue                        // 首页
│   │   ├── login
│   │   │   └── login.vue                       // 登录注册页
│   │   ├── msite
│   │   │   └── msite.vue                       // 商铺列表页
│   │   ├── order
│   │   │   ├── children
│   │   │   │   └── orderDetail.vue             // 订单详情页
│   │   │   └── order.vue                       // 订单列表页
│   │   ├── points
│   │   │   ├── children
│   │   │   │   └── detail.vue                  // 积分说明
│   │   │   └── points.vue                      // 积分页
│   │   ├── profile
│   │   │   ├── children
│   │   │   │   ├── children
│   │   │   │   │   ├── address.vue             // 地址
│   │   │   │   │   └── children
│   │   │   │   │       ├── add.vue             // 新增地址
│   │   │   │   │       └── children
│   │   │   │   │           └── addDetail.vue   // 搜索地址
│   │   │   │   ├── info.vue                    // 帐户信息
│   │   │   │   └── setusername.vue             // 重置用户名
│   │   │   └── profile.vue                     // 个人中心
│   │   ├── search
│   │   │   └── search.vue                      // 搜索页
│   │   ├── service
│   │   │   ├── children
│   │   │   │   └── questionDetail.vue          // 问题详情
│   │   │   └── service.vue                     // 服务中心
│   │   ├── shop
│   │   │   ├── children
│   │   │   │   ├── children
│   │   │   │   │   └── shopSafe.vue            // 商铺认证信息页
│   │   │   │   ├── foodDetail.vue              // 商铺信息页
│   │   │   │   └── shopDetail.vue              // 单个商铺信息页
│   │   │   └── shop.vue                        // 商铺筛选页
│   │   └── vipcard
│   │       ├── children
│   │       │   ├── invoiceRecord.vue           // 购买记录
│   │       │   ├── useCart.vue                 // 使用卡号购买
│   │       │   └── vipDescription.vue          // 会员说明
│   │       └── vipcard.vue                     // 会员卡办理页
│   ├── plugins                                 // 引用的插件
│   ├── router
│   │   └── router.js                           // 路由配置
│   ├── service                                 // 数据交互统一调配
│   │   ├── getData.js                          // 获取数据的统一调配文件,对接口进行统一管理
│   │   └── tempdata                            // 开发阶段的临时数据
│   ├── store                                   // vuex的状态管理
│   │   ├── action.js                           // 配置actions
│   │   ├── getters.js                          // 配置getters
│   │   ├── index.js                            // 引用vuex,创建store
│   │   ├── modules                             // store模块
│   │   ├── mutation-types.js                   // 定义常量muations名
│   │   └── mutations.js                        // 配置mutations
│   └── style
│       ├── common.scss                         // 公共样式文件
│       ├── mixin.scss                          // 样式配置文件
│       └── swiper.min.css
│   ├── App.vue                                 // 页面入口文件
│   ├── main.js                                 // 程序入口文件,加载各种公共组件
├── favicon.ico                                 // 图标
├── index.html  
右下角标签画图:void CRealTime::DrawReportRegion( CDC * pDC )

顶部窗口提示信息:oid CRealTime::OnIndexCurrentChanged( )

画右上角五档信息:int CRealTime::DrawBuySell( CDC * pDC, int xStart, int yStart, int nWidth )

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

 

右上角行情窗口显示流程:

1.切换到激活窗口,执行 OnUpdate()函数。

2.在 OnUpdate()函数中,调用AfxGetProfile().GetCurrentStock(&info)获取股票代码信息,股票信息从不同的容器中获取。

BOOL CStProfile::GetCurrentStock( CStockInfo * pInfo )
{
	if( m_bCurStockFromSList )
		return AfxGetSListStockContainer().GetCurrentStock( pInfo );
	else
		return AfxGetStockContainer().GetCurrentStock( pInfo );
}

用m_realtime[0].PrepareStockData();

m_realtime[0].PrepareStockData()做了下面的事情:

step 2.1.从本地加载分笔数据、分时数据、外部数据3项,2.向通视驱动发起分笔请求。

2.1.1 从本地加载分笔数据

.m_CurStock.PrepareData( CStock::dataReport, CKData::ktypeDay, TRUE );//从本地获取股票分笔成交明细,用于右下角显示成交明细交易记录。

2.1.2 向通视驱动发起分笔数据请求,用于右上角显示在行情子窗口
AfxGetStkReceiver().GetReport( m_CurStock.GetStockInfo(), m_CurStock.GetReport() );

void CRealTimeView::OnUpdate(CView* pSender, LPARAM lHint, CObject* pHint)
{

.....
CStockInfo	info;
	if(AfxGetProfile().GetCurrentStock(&info))
	{
		m_realtime[0].SetCurStock(info);//当前股票
		m_realtime[0].PrepareStockData();
	}
......

}

G:\stock\TskingVS2019\src\Client\StkLib\Src\Profile.cpp

BOOL CStProfile::GetCurrentStock( CStockInfo * pInfo )
{
	if( m_bCurStockFromSList )
		return AfxGetSListStockContainer().GetCurrentStock( pInfo );
	else
		return AfxGetStockContainer().GetCurrentStock( pInfo );
}

G:\stock\TskingVS2019\src\Client\StkLib\Src\Container.cpp

BOOL CStockContainer::GetCurrentStock( CStockInfo * pInfo )
{
	CSPMutex::Scoped	l(m_mutex);

	SP_ASSERT( pInfo );
	if( m_nCurrentStock >= 0 && m_nCurrentStock < GetSize() )
	{
		CStockInfo	& info	=	ElementAt(m_nCurrentStock);
		if( pInfo )
			* pInfo	=	info;
		return TRUE;
	}
	else if( m_strCurrentStockCode.GetLength() > 0 )
	{
		CStockInfo	info;
		info.SetStockCode( CStock::marketUnknown, m_strCurrentStockCode );
		if( pInfo )
			*pInfo	=	info;
		return TRUE;
	}
	return FALSE;
}

step 2.2 数据准备好了,更新stockINfo里面的行情信息

UpdateStockInfoByREPORT( m_CurStock.GetStockInfo(), &(m_CurStock.GetReport().ElementAt(nLen-1)) );//更新股票信息类里面的成交明细,用于在右上角显示行情信息

 

 

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

step 1. 初始化视图结构

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

1.1通过AfxGetStkReceiver().AddRcvDataWnd(GetSafeHwnd());向stkreciever注册了窗口句柄。用来接收主动推送的行情。

1.2 定义了两个定时器,都是向行情服务器发出请求。

大单定时器

行情刷新定时器

int CRealTimeView::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);

	CTSKTabManagerItem* pItem;
	CString	strName;
	//成交记录下面的笔、价、分等
	strName.LoadString(IDS_REALTIMETAB_QUOTE);//笔
	pItem = new CTSKTabManagerItem();
	pItem->SetCaption(strName);
	AddItem(RT_REPORTTAB_QUOTE, pItem);

	strName.LoadString(IDS_REALTIMETAB_PRICE);
	pItem = new CTSKTabManagerItem();
	pItem->SetCaption(strName);
	AddItem(RT_REPORTTAB_PRICE, pItem);

	strName.LoadString(IDS_REALTIMETAB_MINUTE);
	pItem = new CTSKTabManagerItem();
	pItem->SetCaption(strName);
	AddItem(RT_REPORTTAB_MINUTE, pItem);

	strName.LoadString(IDS_REALTIMETAB_BUYSELLEX);
	pItem = new CTSKTabManagerItem();
	pItem->SetCaption(strName);
	AddItem(RT_REPORTTAB_BUYSELLEX, pItem);

	strName.LoadString(IDS_REALTIMETAB_VALUE);
	pItem = new CTSKTabManagerItem();
	pItem->SetCaption(strName);
	AddItem(RT_REPORTTAB_VALUE, pItem);

	strName.LoadString(IDS_REALTIMETAB_DISTRIBUTE);
	pItem = new CTSKTabManagerItem();
	pItem->SetCaption(strName);
	AddItem(RT_REPORTTAB_DISTRIBUTE, pItem);

	strName.LoadString(IDS_REALTIMETAB_BIGTRADE);
	pItem = new CTSKTabManagerItem();
	pItem->SetCaption(strName);
	AddItem(RT_REPORTTAB_BIGTRADE, pItem);

	SetSelectedItem(GetItem(0));

	// m_realtime
	for(int i = 0; i < RTV_MAX_MULTICOUNT; i++)
		m_realtime[i].SetParent(this);

	// 实时行情刷新
	AfxGetStkReceiver().AddRcvDataWnd(GetSafeHwnd());

	// 大单成交刷新频率,改为3秒
	SetTimer(RTV_TIMER_REFRESHBIGTRADE, 3000, NULL);
	SetTimer(RTV_TIMER_REFRESH, 3000, NULL);

	return 0;
}

step 2:初始化视图数据

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

在OnUpdate()函数中,执行了以下动作:

2.1 从本地加载分笔、分笔、外部数据。

2.2 向通视驱动请求分笔数据

 

//第一次初始化
void CRealTimeView::OnInitialUpdate() 
{
	CView::OnInitialUpdate();
	
	// TODO: Add your specialized code here and/or call the base class
	OnUpdate(NULL, UPDATE_HINT_REALTIMEVIEW, NULL);
}

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

	ASSERT(RTV_MAX_MULTICOUNT > 0);

	CStockInfo	info;
	if(AfxGetProfile().GetCurrentStock(&info))
	{
		m_realtime[0].SetCurStock(info);//当前股票
		m_realtime[0].PrepareStockData();
	}
	else
	{
		m_realtime[0].SetCurStock(STKLIB_CODE_MAIN);
		m_realtime[0].PrepareStockData();  //1.从本地加载分笔数据、分时数据、外部数据3项,2.向通视驱动发起分笔请求。
		AfxGetProfile().SetCurrentStock(STKLIB_CODE_MAIN, FALSE);
	}
	if(CRealTime::modeReportDetail == m_realtime[0].GetDrawMode())
		AfxGetStkReceiver().RequestStockData(CStock::dataDetail, &info, 1, 0, 0);
	else
		AfxGetStkReceiver().RequestStockData(CStock::dataMinute, &info, 1, 0, 0);

	// 多股同列
	for(int i=1; i < m_nMultiStockCount && i < RTV_MAX_MULTICOUNT; i++)
	{
		if(AfxGetProfile().GetNextStock(&info))
		{
			m_realtime[i].SetCurStock(info);
			m_realtime[i].PrepareStockData();
			if(CRealTime::modeReportDetail == m_realtime[0].GetDrawMode())
				AfxGetStkReceiver().RequestStockData(CStock::dataDetail, &info, 1, 0, 0);
			else
				AfxGetStkReceiver().RequestStockData(CStock::dataMinute, &info, 1, 0, 0);
		}
	}
	for(int i=1; i < m_nMultiStockCount && i < RTV_MAX_MULTICOUNT; i++)
		AfxGetProfile().GetPrevStock(&info);

	Invalidate();

	/*if(1 == m_nMultiStockCount && CRealTime::modePriceLine == m_realtime[0].GetDrawMode())
		m_wndReportTab.SetWindowPos(NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
	else
		m_wndReportTab.SetWindowPos(NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_HIDEWINDOW);*/

	CMainFrame	* pFrame = AfxGetMainFrame();
	if(pFrame)
		pFrame->m_SearchBox.SetCurrentWindowText();//应该是键盘精灵

	//向行情服务器发起分笔数据请求,bForced=true表示非开盘时间也发起刷新请求
	SendRequestQuote(TRUE);
}

 

 

step 3:在激活窗口时,会调用OnUpdate()函数

//激活窗口事件
void CRealTimeView::OnActivateView(BOOL bActivate, CView* pActivateView, CView* pDeactiveView) 
{
	// TODO: Add your specialized code here and/or call the base class
	if(bActivate)
		OnUpdate(NULL, UPDATE_HINT_REALTIMEVIEW, NULL);

	CView::OnActivateView(bActivate, pActivateView, pDeactiveView);
}

在OnUpdate()函数中,会调用m_realtime[0].PrepareStockData()加载本地数据,

//第一次初始化
void CRealTimeView::OnInitialUpdate() 
{
	CView::OnInitialUpdate();
	
	// TODO: Add your specialized code here and/or call the base class
	OnUpdate(NULL, UPDATE_HINT_REALTIMEVIEW, NULL);
}

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

	ASSERT(RTV_MAX_MULTICOUNT > 0);

	CStockInfo	info;
	if(AfxGetProfile().GetCurrentStock(&info))
	{
		m_realtime[0].SetCurStock(info);//当前股票
		m_realtime[0].PrepareStockData();
	}
	else
	{
		m_realtime[0].SetCurStock(STKLIB_CODE_MAIN);
		m_realtime[0].PrepareStockData();  //1.从本地加载分笔数据、分时数据、外部数据3项,2.向通视驱动发起分笔请求。
		AfxGetProfile().SetCurrentStock(STKLIB_CODE_MAIN, FALSE);
	}
	if(CRealTime::modeReportDetail == m_realtime[0].GetDrawMode())
		AfxGetStkReceiver().RequestStockData(CStock::dataDetail, &info, 1, 0, 0);
	else
		AfxGetStkReceiver().RequestStockData(CStock::dataMinute, &info, 1, 0, 0);

	// 多股同列
	for(int i=1; i < m_nMultiStockCount && i < RTV_MAX_MULTICOUNT; i++)
	{
		if(AfxGetProfile().GetNextStock(&info))
		{
			m_realtime[i].SetCurStock(info);
			m_realtime[i].PrepareStockData();
			if(CRealTime::modeReportDetail == m_realtime[0].GetDrawMode())
				AfxGetStkReceiver().RequestStockData(CStock::dataDetail, &info, 1, 0, 0);
			else
				AfxGetStkReceiver().RequestStockData(CStock::dataMinute, &info, 1, 0, 0);
		}
	}
	for(int i=1; i < m_nMultiStockCount && i < RTV_MAX_MULTICOUNT; i++)
		AfxGetProfile().GetPrevStock(&info);

	Invalidate();

	/*if(1 == m_nMultiStockCount && CRealTime::modePriceLine == m_realtime[0].GetDrawMode())
		m_wndReportTab.SetWindowPos(NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
	else
		m_wndReportTab.SetWindowPos(NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_HIDEWINDOW);*/

	CMainFrame	* pFrame = AfxGetMainFrame();
	if(pFrame)
		pFrame->m_SearchBox.SetCurrentWindowText();//应该是键盘精灵

	//向行情服务器发起分笔数据请求,bForced=true表示非开盘时间也发起刷新请求
	SendRequestQuote(TRUE);
}

读取了分笔、分时数据、外部数据三项。最后,取分笔数据的最后笔,填入stockINfo的行情显示部分。

BOOL CRealTime::PrepareStockData( )
{
	m_CurStock.GetReport().RemoveAll();
	m_CurStock.GetMinute().RemoveAll();
	m_CurStock.GetOutline().RemoveAll();

	// 读取本地文件
	m_CurStock.SetDatabase( &AfxGetDB() );

	// 取得最新行情
	m_CurStock.PrepareData( CStock::dataReport, CKData::ktypeDay, TRUE );
	m_CurStock.PrepareData( CStock::dataMinute, CKData::ktypeDay, TRUE );
	m_CurStock.PrepareData( CStock::dataOutline, CKData::ktypeDay, TRUE );

	AfxGetStkReceiver().GetReport( m_CurStock.GetStockInfo(), m_CurStock.GetReport() );

	int	nLen = m_CurStock.GetReport().GetSize();
	if( nLen > 0 )
		UpdateStockInfoByREPORT( m_CurStock.GetStockInfo(), &(m_CurStock.GetReport().ElementAt(nLen-1)) );
	return TRUE;
}

1.3 向行情服务器请求分笔数据

向行情服务器发起分笔数据请求

在Updata()的最后一句,用void CRealTimeView::SendRequestQuote(BOOL bForced)

//向行情服务器发起分笔数据请求,bForced=true表示非开盘时间也发起刷新请求
void CRealTimeView::SendRequestQuote(BOOL bForced)
{
	BOOL bInTrade = CSPTime::InTradeTime(CSPTime::GetCurrentTime().GetTime(),900);
	CView * pView = AfxGetStaticDoc()->GetActiveView();
	if(bForced || (bInTrade && pView == this))
	{
		for(int i = 0; i < m_nMultiStockCount && i < RTV_MAX_MULTICOUNT; i++)
		{
			CStock & stock = m_realtime[i].GetCurStock();
			CStockInfo & info = stock.GetStockInfo();
			if(info.IsValidStock())
				AfxGetStkReceiver().RequestStockData(CStock::dataReport, &info, 1, 0, 0);
		}
	}
}

调用AfxGetStkReceiver().RequestStockData(),它又是调用的int nRet = gNetTSDLL.RequestStockData(nDataTypeTS, pStocks, nSize, nKType, nDataCount);

int CStkReceiver::RequestStockData(int nDataType/*CStock::DataType*/, CStockInfo * pStockInfo, int nSize, int nKType, int nDataCount) //向行情服务器发起分笔数据请求
{
	int nDataTypeTS = DataType_to_TSDataType(nDataType);

	if (nSize < 0)
		return 0;

	STOCK_STRUCTEx * pStocks = new STOCK_STRUCTEx[nSize+1];
	memset(pStocks, 0, sizeof(STOCK_STRUCTEx)*(nSize+1));
	
	for(int i=0; i<nSize; i++)
	{
		pStocks[i].m_type = (BYTE)pStockInfo[i].GetType();
		strncpy(pStocks[i].m_code, pStockInfo[i].GetStockCode(), sizeof(pStocks[i].m_code));
	}
	int nRet = gNetTSDLL.RequestStockData(nDataTypeTS, pStocks, nSize, nKType, nDataCount);//调用 gNetTSDLL.RequestStockData()

	delete [] pStocks;
	return nRet;
}

 

NetTs调用CTWSocket::GetInstance().RequestStockData( nDataType, pStocks, nSize, nKType, nDataCount )

int WINAPI	RequestStockData( int nDataType, TW_STOCK * pStocks, int nSize, int nKType, int nDataCount )
{
	return CTWSocket::GetInstance().RequestStockData( nDataType, pStocks, nSize, nKType, nDataCount );
}

 

根据请求的数据类型发送请求

int CTWSocket::RequestStockData(int nDataType, TW_STOCK* pStocks, int nSize, int nKType, int nDataCount)
{
	//判断是否正在接收数据,
	if (m_bIsReceiving && time(NULL) - m_timeReceiveLast > 60) //离上一次接收数据的时间要超过60秒 
		m_bIsReceiving = FALSE;

	//如果正在接收数据,则推入队列,立即返回。
	if (m_bIsReceiving)
	{
		CTWCommand cmd(nDataType, pStocks, nSize, nKType, nDataCount);
		PushCommand(cmd);
		return nSize;
	}

	//OnNewCommand的作用是先推入再弹出
	int nRet = 0;
	switch (nDataType)
	{
	case RCV_REPORT:
		if (OnNewCommand(nDataType, pStocks, 0))
			nRet = RequestReport(pStocks, nSize);
		break;
	case FILE_HISTORY_EX:
		if (OnNewCommand(nDataType, pStocks, 300))
			nRet = RequestHistory(pStocks, nSize, nKType, nDataCount);
		break;
	case FILE_MINUTE_EX:
		if (OnNewCommand(nDataType, pStocks, 60))
			nRet = RequestMinute(pStocks, nSize);
		break;
	case FILE_POWER_EX:
		if (OnNewCommand(nDataType, pStocks, 300))
			nRet = RequestPower(pStocks, nSize);
		break;
	case FILE_MULTISORT_EX:
		if (OnNewCommand(nDataType, pStocks, 0))
			nRet = RequestMultisort(pStocks, nSize);
		break;
	case FILE_DETAIL_EX:
		if(OnNewCommand(nDataType, pStocks, 60))
			nRet = RequestDetail(pStocks, nSize);
		break;
	case FILE_BASE_EX:
		if (OnNewCommand(nDataType, pStocks, 300))
			nRet = RequestBase(pStocks, nSize);
		break;
	case FILE_NEWS_EX:
		if (OnNewCommand(nDataType, pStocks, 60))
			nRet = RequestNews(pStocks, nSize);
		break;
	case FILE_HTML_EX:
		if (OnNewCommand(nDataType, pStocks, 60))
			nRet = RequestHtml(pStocks, nSize);
		break;
	case FILE_SOFTWARE_EX:
		if (OnNewCommand(nDataType, pStocks, 60))
			nRet = RequestSoftware(pStocks, nSize);
		break;
	case FILE_SHAZQDATA_EX:
		if (OnNewCommand(nDataType, pStocks, 60))
			nRet = RequestShazqdata(pStocks, nSize);
		break;
	default:
		break;
	}

	return nRet;
}

 

1.4 数据的接收及处理

1.4.1 循环各个股票,调用

/有数据传过来
LRESULT CRealTimeView::OnStkReceiverData(WPARAM wParam, LPARAM lParam)
{
	for(int i = 0; i < m_nMultiStockCount && i < RTV_MAX_MULTICOUNT; i++)
		m_realtime[i].OnStkReceiverData(wParam,lParam);
	return 0;
}

只对分时数据和分笔数据进行处理

//接收数据的消息处理函数
LRESULT CRealTime::OnStkReceiverData( WPARAM wParam, LPARAM lParam )
{
	PCOMMPACKET	pCommPacket	= (PCOMMPACKET)lParam;

	switch( wParam )
	{
	case CStock::dataReport:
		if( pCommPacket && CStock::dataReport == pCommPacket->m_dwDataType )
		{
			BOOL	bInv = FALSE;
			for(DWORD i=0; i<pCommPacket->m_dwCount; i++)
			{
				if( m_CurStock.GetStockInfo().IsEqualTo( pCommPacket->m_pReport[i].m_dwMarket, pCommPacket->m_pReport[i].m_szCode ) )
				{
					UpdateStockInfoByREPORT( m_CurStock.GetStockInfo(), &(pCommPacket->m_pReport[i]) );
					if( -1 != m_CurStock.GetReport().InsertReportSort( pCommPacket->m_pReport[i] ) )
					{
						MINUTE	minute;
						if( convert_REPORT_to_MINUTE( &(pCommPacket->m_pReport[i]), &minute ) )
							m_CurStock.GetMinute().InsertMinuteSort( minute );
						m_nCurrentStartPos	= -1;
						bInv = TRUE;
					}
				}
			}
			if( bInv && m_pParent && ::IsWindow(m_pParent->GetSafeHwnd()) )
				m_pParent->Invalidate();
		}
		break;
	case CStock::dataMinute:
		if( pCommPacket && CStock::dataMinute == pCommPacket->m_dwDataType )
		{
			int	nOldSize	= m_CurStock.GetMinute().GetSize();
			for(DWORD i=0; i<pCommPacket->m_dwCount; i++)
			{
				if( m_CurStock.GetStockInfo().IsEqualTo( pCommPacket->m_pMinute[i].m_dwMarket, pCommPacket->m_pMinute[i].m_szCode ) )
					m_CurStock.GetMinute().InsertMinuteSort( pCommPacket->m_pMinute[i] );
			}
			if( nOldSize != m_CurStock.GetMinute().GetSize() && m_pParent && ::IsWindow(m_pParent->GetSafeHwnd()) )
			{
				m_nCurrentStartPos	= -1;
				m_pParent->Invalidate();
			}
		}
		break;
	}
	return 0L;
}

1.确定显示股票分时图的股票目标

int m_nMultiStockCount

CRealTimeView类定义了一个变量int m_nMultiStockCount;显示多只股票的个数,由void CRealTimeView::ShowMultiStock(int nMultiStockCount)函数设置。

G:\stock\TskingVS2019\src\Client\StkUI\View\RealTimeView.h

#define	RTV_MAX_MULTICOUNT 9

class CRealTimeView : public CView, public CTSKTabManager
{
	DECLARE_DYNCREATE(CRealTimeView)
protected:
	CRealTimeView();
	virtual ~CRealTimeView();

protected:
	int m_nMultiStockCount;//显示多只股票的个数,由void CRealTimeView::ShowMultiStock(int nMultiStockCount)函数设置 2019/06/08 by freeman
	CRealTime m_realtime[RTV_MAX_MULTICOUNT];

 

画图部分说明

1.CRealTime

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

分时线,多股同列的分时线。

 

负责画图

void CRealTime::Redraw( CDC * pDC, CRect rectAll )
{
	ASSERT( m_pParent && ::IsWindow( m_pParent->GetSafeHwnd() ) );
	if( !m_pParent || !::IsWindow(m_pParent->GetSafeHwnd()) )
		return;

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

	ResetClient( rectAll );
	pDC->FillSolidRect( &rectAll, AfxGetProfile().GetColor(CColorClass::clrGraphBK) );

	if( CRealTime::modePriceLine == m_nDrawMode )
	{
		DrawPriceVolume( pDC );
		DrawLBDK( pDC );
		DrawMMLD( pDC );
		DrawReportRegion( pDC );
			
		DrawSelectionLine( pDC, TRUE );
		OnIndexCurrentChanged( );
	}
	else if( CRealTime::modeReportDetail == m_nDrawMode )
	{
		DrawReportDetail( pDC );
	}
	else if( CRealTime::modeMinuteDetail == m_nDrawMode )
	{
		DrawMinuteDetail( pDC );
	}
	else if( CRealTime::modeBigTradeDetail == m_nDrawMode )
	{
		DrawBigTradeDetail( pDC );
	}
}

 

void CRealTime::DrawReportRegion( 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( CRealTime::modePriceLine == m_nDrawMode )
	{
		switch( m_nReportWhat )
		{
		case CRealTime::reportQuote:		DrawReportQuote(pDC);			break;//笔
		case CRealTime::reportPrice:		DrawReportPrice(pDC);			break;//价
		case CRealTime::reportMinute:		DrawReportMinute(pDC);		break;//分
		case CRealTime::reportBuySellEx:	DrawReportBuySellEx(pDC);		break;//盘 8档
		case CRealTime::reportValue:		DrawReportValue(pDC);			break;//值
		case CRealTime::reportDistribute:	DrawReportDistribute(pDC);	break;//筹
		case CRealTime::reportBigTrade:		DrawReportBigTrade(pDC);    break;//单
		}
	}
}

分时图画窗口顶部的时间 价格 成交量等信息

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

void CRealTime::OnIndexCurrentChanged( )
{
	if( CRealTime::modePriceLine != m_nDrawMode )
		return;

	DECLARE_COLOR_DEFINATION

	if( !m_pParent || !::IsWindow(m_pParent->GetSafeHwnd()) )
		return;
	
	CClientDC	dc(m_pParent);
	CDC	*pDC	= &dc;

	CRect	rectTop(m_rectPrice.left+135,m_rectAll.top,m_rectPrice.right,m_rectPrice.top-1 );
	pDC->FillSolidRect( &rectTop, clrBK );
	
	if( m_nIndexCurrent < 0 || m_nIndexCurrent >= m_CurStock.GetMinute().GetSize() )
		return;
	
	MINUTE	minute	= m_CurStock.GetMinute().ElementAt(m_nIndexCurrent);

	// Fill Background
	pDC->SetBkColor( clrBK );

	CString	strTemp;
	CFont	* pOldFont	= AfxSelectDCFont( pDC, 12 );

	int	x	= rectTop.left;
	int	y	= rectTop.top + 4;
	int	right	= rectTop.right-100;
	pDC->SetTextColor( clrText );
	strTemp.LoadString( IDS_REALTIME_TIME );
	if( x < right )		pDC->TextOut( x, y,   strTemp );
	strTemp.LoadString( IDS_REALTIME_PRICE );
	if( x+80 < right )	pDC->TextOut( x+80, y,  strTemp );
	strTemp.LoadString( IDS_REALTIME_VOLUME );
	if( x+160 < right )	pDC->TextOut( x+160, y,  strTemp );
	strTemp.LoadString( IDS_REALTIME_AMOUNT );
	if( x+290 < right )	pDC->TextOut( x+290, y,  strTemp );
	
	//分时图画窗口顶部的时间 价格 成交量等信息 by freeman

	// Time
	CSPTime	time(minute.m_time);
	strTemp	= time.Format( "%H:%M" );
	pDC->SetTextColor( clrPlane );
	if( x+30 < right )	pDC->TextOut( x+30, y, strTemp );

	// Price
	CString strPriceFmt;
	strPriceFmt.Format( "%%.%df", m_CurStock.GetStockInfo().DigitBit() );
	strTemp.Format( strPriceFmt, minute.m_fNew );
	pDC->SetTextColor( RT_DETERMINE_COLOR( minute.m_fNew, m_CurStock.GetStockInfo().m_fLast ) );
	if( x+110 < right )	pDC->TextOut( x+110, y, strTemp );
	
	// Volume
	double	dVolume	= minute.m_fVolume;
	if( m_nIndexCurrent > 0 )
		dVolume	-= m_CurStock.GetMinute()[m_nIndexCurrent-1].m_fVolume;
	strTemp.Format( "%.0f", dVolume*0.01 );
	pDC->SetTextColor( clrTitle );
	if( x+220 < right )	pDC->TextOut( x+220, y, strTemp );
	
	// Amount
	double	dAmount	= minute.m_fAmount;
	if( m_nIndexCurrent > 0 )
		dAmount	-= m_CurStock.GetMinute()[m_nIndexCurrent-1].m_fAmount;
	strTemp.Format( "%.2f", dAmount*0.001 );
	pDC->SetTextColor( clrTitle );
	if( x+350 < right )	pDC->TextOut( x+350, y, strTemp );

	pDC->SelectObject( pOldFont );
}

2.G:\stock\TskingVS2019\src\Client\StkUI\View\RealTimeView.cpp

成交明细由接口Loadreport提供明细数据(按F1时)

//实时行情,画右上角信息
int CRealTime::DrawBuySell( CDC * pDC, int xStart, int yStart, int nWidth )
////////////////////////////////////////////////////////////////////////////
//      函 数 名: CRealTime::DrawBuySellEx()
//      功能说明:实时行情,画右上角买卖成交信息,8档行情 by freeman
//      入口参数:
//      出口参数:
//      返回参数:
////////////////////////////////////////////////////////////////////////////
int CRealTime::DrawBuySellEx( CDC * pDC, int xStart, int yStart, int nWidth )

:Redraw->DrawReportRegion( pDC )->DrawReportQuote( pDC );

DrawReportQuote( pDC )
{
...
int nBuySellHeight = DrawBuySell( pDC, m_rectReport.left, m_rectReport.top, m_rectReport.Width() );//画右上角5档信息,返回总高度,下面的框用此高度继续
DrawReportColumn( pDC, info, aReport, m_nCurrentStartPos, m_nCurrentPageCount, rect );//画右下角“笔”成交明细
....
}

 

接收的到数据时的处理

1.stkReciver会管理通视驱动和行情服务器驱动

2.发送消息

3.接收数据消息

由LRESULT CSListView::OnStkReceiverData(WPARAM wParam, LPARAM lParam)负责处理

 

其他

#define IDS_REALTIME_TITLE              45914
#define IDS_REALTIME_BSRATIO            45915
#define IDS_REALTIME_BSDIFF             45916
#define IDS_REALTIME_SELL5              45917
#define IDS_REALTIME_SELL4              45918
#define IDS_REALTIME_SELL3              45919
#define IDS_REALTIME_SELL2              45920
#define IDS_REALTIME_SELL1              45921
#define IDS_REALTIME_BUY1               45922
#define IDS_REALTIME_BUY2               45923
#define IDS_REALTIME_BUY3               45924
#define IDS_REALTIME_BUY4               45925
#define IDS_REALTIME_BUY5               45926
#define IDS_REALTIME_PRICENOW           45927
#define IDS_REALTIME_PRICEAVE           45928
#define IDS_REALTIME_PRICEDIFF          45929
#define IDS_REALTIME_PRICEOPEN          45930
#define IDS_REALTIME_PRICEDIFFPERCENT   45931
#define IDS_REALTIME_PRICEHIGH          45932
#define IDS_REALTIME_VOLSUM             45933
#define IDS_REALTIME_PRICELOW           45934
#define IDS_REALTIME_VOLNOW             45935
#define IDS_REALTIME_VOLRATION          45936
#define IDS_REALTIME_VOLOUTER           45937
#define IDS_REALTIME_VOLINNER           45938
#define IDS_REALTIME_TIME               45939
#define IDS_REALTIME_PRICE              45940
#define IDS_REALTIME_VOLUME             45941
#define IDS_REALTIME_AMOUNT             45942
#define IDS_REALTIME_ADVANCE            45943
#define IDS_REALTIME_DECLINE            45944
#define IDS_REALTIME_LBDK               45945
#define IDS_REALTIME_MMLD               45946
#define IDS_REALTIME_REPORTDETAILTITLE  45947
#define IDS_REALTIME_MINUTEDETAILTITLE  45948
#define IDS_REALTIME_BIGTRADEDETAILTITLE 45949
#define IDS_REALTIME_STOCKNAME          45950
#define IDS_REALTIMETAB_QUOTE           45951
#define IDS_REALTIMETAB_PRICE           45952
#define IDS_REALTIMETAB_MINUTE          45953
#define IDS_REALTIMETAB_BUYSELLEX       45954
#define IDS_REALTIMETAB_VALUE           45955
#define IDS_REALTIMETAB_DISTRIBUTE      45956
#define IDS_REALTIMETAB_BIGTRADE        45957
#define IDS_REALTIME_RISINGLIMIT        45958
#define IDS_REALTIME_FALLINGLIMIT       45959
#define IDS_REALTIME_AH                 45960
#define IDS_REALTIME_NH                 45961
#define IDS_REALTIME_NL                 45962
#define IDS_REALTIME_AL                 45963
#define IDS_REALTIME_SELL8              45964
#define IDS_REALTIME_SELL7              45965
#define IDS_REALTIME_SELL6              45966
#define IDS_REALTIME_BUY6               45967
#define IDS_REALTIME_BUY7               45968
#define IDS_REALTIME_BUY8               45969
STRINGTABLE
BEGIN
    IDS_SIMUREALOP_EXPLAINNEXTOP "下一步操作是操作计划,成功后自动加入历史操作记录。"
    IDS_SIMUREALOP_EXPLAINOPRECORD "操作记录中的股票单价是向下复权后的数值。"
    IDS_SIMUREALOP_TIMEEXPLAINFMT "现在日期是%s,请在下一交易日集合竞价时间(9:15-9:25)进行以上委托。"
    IDS_SIMUREPORT_BUYPRICE "买入价"
    IDS_SIMUREPORT_NOWPRICE "现价"
    IDS_STRATEGY_SETRULELONG "设置长周期指标参数"
    IDS_STRATEGY_SETRULEINDEX "设置大盘指标参数"
    IDS_SIMUADVANCED_NOTNUMBER "请在止损和止赢编辑框中输入数字。"
    IDS_SIMUADVANCED_NOSELECTEDLONG "没有选中的长周期指标。请点击按钮“选择长周期指标”来进行选择。"
    IDS_SIMUADVANCED_NOSELECTEDINDEX "没有选中的大盘指标。请点击按钮“选择大盘指标”来进行选择。"
    IDS_REALTIME_TITLE      "分时行情"
    IDS_REALTIME_BSRATIO    "委比"
    IDS_REALTIME_BSDIFF     "委差"
    IDS_REALTIME_SELL5      "卖⑤"
    IDS_REALTIME_SELL4      "卖④"
    IDS_REALTIME_SELL3      "卖③"
END

STRINGTABLE
BEGIN
    IDS_REALTIME_SELL2      "卖②"
    IDS_REALTIME_SELL1      "卖①"
    IDS_REALTIME_BUY1       "买①"
    IDS_REALTIME_BUY2       "买②"
    IDS_REALTIME_BUY3       "买③"
    IDS_REALTIME_BUY4       "买④"
    IDS_REALTIME_BUY5       "买⑤"
    IDS_REALTIME_PRICENOW   "成交"
    IDS_REALTIME_PRICEAVE   "均价"
    IDS_REALTIME_PRICEDIFF  "涨跌"
    IDS_REALTIME_PRICEOPEN  "开盘"
    IDS_REALTIME_PRICEDIFFPERCENT "幅度"
    IDS_REALTIME_PRICEHIGH  "最高"
    IDS_REALTIME_VOLSUM     "总手"
    IDS_REALTIME_PRICELOW   "最低"
    IDS_REALTIME_VOLNOW     "现手"
END

STRINGTABLE
BEGIN
    IDS_REALTIME_VOLRATION  "量比"
    IDS_REALTIME_VOLOUTER   "外盘"
    IDS_REALTIME_VOLINNER   "内盘"
    IDS_REALTIME_TIME       "时间"
    IDS_REALTIME_PRICE      "价格"
    IDS_REALTIME_VOLUME     "量(手)"
    IDS_REALTIME_AMOUNT     "额(千元)"
    IDS_REALTIME_ADVANCE    "涨家数"
    IDS_REALTIME_DECLINE    "跌家数"
    IDS_REALTIME_LBDK       "量比(多空)"
    IDS_REALTIME_MMLD       "买卖力道"
    IDS_REALTIME_REPORTDETAILTITLE "每笔成交明细  PageUp:上翻 PageDown:下翻"
    IDS_REALTIME_MINUTEDETAILTITLE "分钟成交明细  PageUp:上翻 PageDown:下翻"
    IDS_REALTIME_BIGTRADEDETAILTITLE "大单成交明细  PageUp:上翻 PageDown:下翻"
    IDS_REALTIME_STOCKNAME  "名称"
    IDS_REALTIMETAB_QUOTE   "笔"
END
STRINGTABLE
BEGIN
    IDS_REALTIMETAB_PRICE   "价"
    IDS_REALTIMETAB_MINUTE  "分"
    IDS_REALTIMETAB_BUYSELLEX "盘"
    IDS_REALTIMETAB_VALUE   "值"
    IDS_REALTIMETAB_DISTRIBUTE "筹"
    IDS_REALTIMETAB_BIGTRADE "单"
    IDS_REALTIME_RISINGLIMIT "涨停价"
    IDS_REALTIME_FALLINGLIMIT "跌停价"
    IDS_REALTIME_AH         "AH"
    IDS_REALTIME_NH         "NH"
    IDS_REALTIME_NL         "NL"
    IDS_REALTIME_AL         "AL"
    IDS_REALTIME_SELL8      "卖⑧"
    IDS_REALTIME_SELL7      "卖⑦"
    IDS_REALTIME_SELL6      "卖⑥"
    IDS_REALTIME_BUY6       "买⑥"
END

STRINGTABLE
BEGIN
    IDS_REALTIME_BUY7       "买⑦"
    IDS_REALTIME_BUY8       "买⑧"
END