股票行情接收由src\StkNet\Src\StkReceiver.cpp来实现
1.推送行情
static CSTKDRVContainer gSTOCKDLL;
CSTKDRVContainer在src\StkNet\Src\STKDRVContainer.cpp实现,主要功能:
1.加载第三方驱动(如通视的dll,银江的dll)
2.向stkui主程序相关的目标窗口句柄发送行情数据包()
2.点播行情
static CNetSTKDRV gNetTSDLL;
当点击“连接行情服务器时”,
BOOL CStkReceiver::NetEngineBeginWorking(LPCTSTR lpszAddress, UINT nPort, LPCTSTR lpszUser, LPCTSTR lpszPasswd)
{
if (gNetTSDLL.LoadDriver("NetTS.dll")
&& gNetTSDLL.Stock_Init_Nodialog(m_hWnd,WM_APP_STKRECEIVER_TSDATA,RCV_WORK_SENDMSG,
lpszAddress,nPort,lpszUser,lpszPasswd) > 0)
return TRUE;
return FALSE;
}
2.分时图对行情数据的处理
2.1 RealTime.cpp分时图行情对接收到的数据的处理
2.2 分时图处理行情数据
对收到的行情数据,只对成交明细数据dataReport和分时线数据进行处理。
G:\stock\TskingVS2019\src\Client\StkUI\View\RePlayRealTime.cpp
//接收数据的消息处理函数
LRESULT CRePlayRealTime::OnStkReceiverData( WPARAM wParam, LPARAM lParam )
{
PCOMMPACKET pCommPacket = (PCOMMPACKET)lParam;
switch( wParam )
{
case CStock::dataReport:
case CStock::dataMinute:
}
}
2.2.1 对分笔数据的处理
接收数据的消息处理函数,分时图对行情数据的处理,对收到的行情数据,只对成交明细数据dataReport和分时线数据进行处理。
只更新了股票StockInfo中的卖一等和驲K线数据。插入了分笔数据,插入了分时数据。对其他分钟线和日K线数据未做处理。
//接收数据的消息处理函数,分时图对行情数据的处理,对收到的行情数据,只对成交明细数据dataReport和分时线数据进行处理。
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++)
{
//判断数据是否是当前股票分笔数据 by freeman
if( m_CurStock.GetStockInfo().IsEqualTo( pCommPacket->m_pReport[i].m_dwMarket, pCommPacket->m_pReport[i].m_szCode ) )
{
//更新了股票StockInfo中的卖一等和K线数据。
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;
3.K线图数据处理
K线图收到数据后,交给CStockGraph::OnStkReceiverData(WPARAM wParam, LPARAM lParam)处理
G:\stock\TskingVS2019\src\Client\StkUI\View\GraphView.cpp
LRESULT CGraphView::OnStkReceiverData(WPARAM wParam, LPARAM lParam)
{
return m_graph.OnStkReceiverData(wParam,lParam);
}
G:\stock\TskingVS2019\src\Client\StkUI\View\StockGraph.cpp
//周期图数据消息接收处理,只对分笔数据、分时数据、K线数据进行处理 by freeman
LRESULT CStockGraph::OnStkReceiverData(WPARAM wParam, LPARAM lParam)
{
PCOMMPACKET pCommPacket = (PCOMMPACKET)lParam;
switch (wParam)
{
case CStock::dataReport:
if (pCommPacket && CStock::dataReport == pCommPacket->m_dwDataType)
{
DWORD i;
for (i = 0; i < pCommPacket->m_dwCount; i++)
{
if (m_CurStock.GetStockInfo().IsEqualTo(pCommPacket->m_pReport[i].m_dwMarket, pCommPacket->m_pReport[i].m_szCode))
break;
}
if (i != pCommPacket->m_dwCount)
{
// 加入最新一天的K线数据
PrepareStockData(TRUE);
if (m_pParent && ::IsWindow(m_pParent->GetSafeHwnd()))
m_pParent->Invalidate();
}
}
break;
case CStock::dataK:
if (pCommPacket && CStock::dataK == pCommPacket->m_dwDataType)
{
DWORD i;
for (i = 0; i < pCommPacket->m_dwCount; i++)
{
if (m_CurStock.GetStockInfo().IsEqualTo(pCommPacket->m_pKdata[i].m_dwMarket, pCommPacket->m_pKdata[i].m_szCode))
break;
}
if (i != pCommPacket->m_dwCount)
{
// 加入最新一天的K线数据
PrepareStockData(TRUE);
if (m_pParent && ::IsWindow(m_pParent->GetSafeHwnd()))
m_pParent->Invalidate();
}
}
break;
case CStock::dataMinute:
// WILLCHECK
if (!CKData::IsDayOrMin(m_nCurKType) && pCommPacket && CStock::dataMinute == pCommPacket->m_dwDataType)
{
int nOldSize = m_CurStock.GetMinute().GetSize();
DWORD i;
for (i = 0; i < pCommPacket->m_dwCount; i++)
{
if (m_CurStock.GetStockInfo().IsEqualTo(pCommPacket->m_pMinute[i].m_dwMarket, pCommPacket->m_pMinute[i].m_szCode))
break;
}
if (i != pCommPacket->m_dwCount)
{
// 加入最新的分钟K线数据
PrepareStockData(TRUE);
if (m_pParent && ::IsWindow(m_pParent->GetSafeHwnd()))
m_pParent->Invalidate();
}
}
break;
}
return 0L;
}
4.SlistView对接收数据的处理
G:\stock\TskingVS2019\src\Client\StkUI\View\SListView.cpp
//前面定义了ON_MESSAGE(WM_APP_STKRECEIVER_DATA, OnStkReceiverData)的消息,处理接收到的消息 2019/06/08 by freeman
LRESULT CSListView::OnStkReceiverData(WPARAM wParam, LPARAM lParam)
{
PCOMMPACKET pCommPacket = (PCOMMPACKET)lParam;
switch (wParam)
{
case CStock::dataReport:
if (pCommPacket && CStock::dataReport == pCommPacket->m_dwDataType
&& pCommPacket->m_dwCount > 0)
{
CStockContainer& container = AfxGetSListStockContainer();
// 如果当前股票列表显示的日期不是今天的,返回,不做刷新
DWORD dwDate = -1;;
AfxGetSListStockContainer().GetCurrentType(NULL, NULL, &dwDate);
//发过来的明细日期不是当天的则丢弃
if (-1 != dwDate && dwDate != CSPTime(pCommPacket->m_pReport[0].m_time).ToStockTimeDay())
return 0L;
container.Lock();
// 刷新数据
BOOL bNeedReSort = FALSE;
for (DWORD i = 0; i < pCommPacket->m_dwCount; i++)
{
int id = 0;//股票在容器中的id号
if (container.GetStockInfo(pCommPacket->m_pReport[i].m_szCode, NULL, &id))
{
CStockInfo& info = container.ElementAt(id);//取得股票信息
UpdateStockInfoByREPORT(info, &(pCommPacket->m_pReport[i]));//更新成交明细数据
StockInfoChanged(id, info);//更新股票容器数据,id为股票在容器中的id号,info 为新的股票信息
bNeedReSort = TRUE;
}
}
// 统计平均值刷新
if (bNeedReSort)
{
container.SetAverage();
//SetAverageItem(m_Grid, container, TRUE);
}
// 重新排序
if (-1 != m_nColSort && bNeedReSort)
{
LPARAM lParam = m_Grid.GetItemData(0, m_nColSort);
if (lParam >= 0)
{
CStockContainer::m_pSortContainer = &container;
container.m_nSortVariantID = lParam;
container.m_bSortAscend = m_bSortAscend;
m_Grid.SortItems(ItemCompareFunc, 0, TRUE);
}
m_Grid.Invalidate();//Invalidate只是放一个WM_PAINT消息在队列里。
}
container.UnLock();
}
break;
}
return 0L;
}
合并当日K线数据
G:\stock\TskingVS2019\src\Client\StkLib\Src\Packets.cpp
//实时更新CStockContainer日线数据
BOOL UpdateStockContainerByKData( CStockContainer &container, LPCTSTR lpszCode, CKData & kdata )
{
container.Lock();
int id = 0;
if( CKData::ktypeDay == kdata.GetKType()
&& container.GetStockInfo( lpszCode, NULL, &id ) )
{
CStockInfo & info = container.ElementAt(id);
if( kdata.GetSize() > (int)AfxGetProfile().GetCacheDays() )
{
// 只使用AfxGetProfile().GetCacheDays()天的数据
CKData temp( kdata.GetKType() );
for( int i=kdata.GetSize()-AfxGetProfile().GetCacheDays(); i<kdata.GetSize(); i++ )
temp.Add( kdata.ElementAt(i) );
//合并当日K线数据 by freeman
info.m_kdata.MergeKData( &temp );
}
else
//合并当日K线数据 by freeman
info.m_kdata.MergeKData( &kdata );
// 指数涨跌家数
int nSize = info.m_kdata.GetSize();
if( nSize > 0 )
{
info.m_dwAdvance = info.m_kdata.ElementAt(nSize-1).m_dwAdvance;
info.m_dwDecline = info.m_kdata.ElementAt(nSize-1).m_dwDecline;
}
}
container.UnLock();
return TRUE;
}
G:\stock\TskingVS2019\src\Client\StkLib\Src\AfxCore.cpp
BOOL AfxReloadStock( CStock & stock )
{
CStockInfo info = stock.GetStockInfo();
// Reload AfxGetStockMain()
AfxGetStockContainer().GetStockInfo( info.GetStockCode(), &info );
stock.Clear( );
stock.SetStockInfo( &info );
stock.SetDatabase( &AfxGetDB() );
stock.PrepareData( CStock::dataK, CKData::ktypeDay );
// Merge New 合并StockInfo的日K线数据
stock.GetKDataDay().MergeKData( &(info.m_kdata) );
stock.PrepareData( CStock::dataK, CKData::ktypeWeek );
stock.PrepareData( CStock::dataK, CKData::ktypeMonth );
stock.PrepareData( CStock::dataK, CKData::ktypeMin1);//extend 1分钟K线 by freeman
stock.PrepareData( CStock::dataK, CKData::ktypeMin5 );
stock.PrepareData( CStock::dataK, CKData::ktypeMin15 );
stock.PrepareData( CStock::dataK, CKData::ktypeMin30 );
stock.PrepareData( CStock::dataK, CKData::ktypeMin60 );
return TRUE;
}
BOOL AfxPrepareStockData( CStDatabase * pDatabase, CStock &stock, int nKType, int nKFormat, int nMaindataType, BOOL bFullFill, BOOL bReload )
{
CStockInfo info;
if( !AfxGetStockContainer().GetStockInfo( stock.GetStockCode(), &info ) )
info = stock.GetStockInfo( );
stock.SetDatabase( pDatabase );
stock.PrepareData( CStock::dataK, CKData::ktypeDay, bReload );
//stock.PrepareData(CStock::dataK, CKData::ktypeMin1, bReload);//extend 1分钟K线 by freeman
stock.PrepareData( CStock::dataK, CKData::ktypeMin5, bReload );
stock.PrepareData( CStock::dataDR, CKData::ktypeDay, bReload );
if( bReload || stock.GetKDataDay().GetCurFormat() == CKData::formatOriginal )
//对当日日K线数据进行合并
stock.GetKDataDay().MergeKData( &(info.m_kdata) );
G:\stock\TskingVS2019\src\Client\StkLib\Src\Stock.cpp
//合并K先数据
int CStock::MergeKData(CStock & stock, int period)
{
CKData* pkdata = NULL;
CKData* pkdata2 = NULL;
switch (period)
{
case CKData::ktypeMonth:
pkdata = &(GetKDataMonth());
pkdata2 = &(stock.GetKDataMonth());
break;
case CKData::ktypeWeek:
pkdata = &(GetKDataWeek());
pkdata2 = &(stock.GetKDataWeek());
break;
case CKData::ktypeDay:
pkdata = &(GetKDataDay());
pkdata2 = &(stock.GetKDataDay());
break;
case CKData::ktypeMin60:
pkdata = &(GetKDataMin60());
pkdata2 = &(stock.GetKDataMin60());
break;
case CKData::ktypeMin30:
pkdata = &(GetKDataMin30());
pkdata2 = &(stock.GetKDataMin30());
break;
case CKData::ktypeMin15:
pkdata = &(GetKDataMin15());
pkdata2 = &(stock.GetKDataMin15());
break;
case CKData::ktypeMin5:
pkdata = &(GetKDataMin5());
pkdata2 = &(stock.GetKDataMin5());
break;
case CKData::ktypeMin1://extend 1分钟K线 by freeman
pkdata = &(GetKDataMin1());
pkdata2 = &(stock.GetKDataMin1());
break;
default:
SP_ASSERT(FALSE);
return 0;
}
return pkdata->MergeKData(pkdata2);
}
合并K线数据
G:\tmp\stock\TskingVS2019\src\Client\StkLib\Src\AfxCore.cpp
BOOL AfxReloadStock( CStock & stock )
{
CStockInfo info = stock.GetStockInfo();
// Reload AfxGetStockMain()
AfxGetStockContainer().GetStockInfo( info.GetStockCode(), &info );
stock.Clear( );
stock.SetStockInfo( &info );
stock.SetDatabase( &AfxGetDB() );
stock.PrepareData( CStock::dataK, CKData::ktypeDay );
// Merge New 合并StockInfo的日K线数据
stock.GetKDataDay().MergeKData( &(info.m_kdata) );
stock.PrepareData( CStock::dataK, CKData::ktypeWeek );
stock.PrepareData( CStock::dataK, CKData::ktypeMonth );
stock.PrepareData( CStock::dataK, CKData::ktypeMin1);//extend 1分钟K线 by freeman 加载1分钟数据是否需要性能优化?
stock.PrepareData( CStock::dataK, CKData::ktypeMin5 );
stock.PrepareData( CStock::dataK, CKData::ktypeMin15 );
stock.PrepareData( CStock::dataK, CKData::ktypeMin30 );
stock.PrepareData( CStock::dataK, CKData::ktypeMin60 );
return TRUE;
}
G:\tmp\stock\TskingVS2019\src\Client\StkLib\Src\Packets.cpp
//实时合并CStockContainer的stockinfo日K线缓存数据数据
BOOL UpdateStockContainerByKData( CStockContainer &container, LPCTSTR lpszCode, CKData & kdata )
{
container.Lock();
int id = 0;
if( CKData::ktypeDay == kdata.GetKType()
&& container.GetStockInfo( lpszCode, NULL, &id ) )
{
CStockInfo & info = container.ElementAt(id);
if( kdata.GetSize() > (int)AfxGetProfile().GetCacheDays() )
{
// 只使用AfxGetProfile().GetCacheDays()天的数据
CKData temp( kdata.GetKType() );
for( int i=kdata.GetSize()-AfxGetProfile().GetCacheDays(); i<kdata.GetSize(); i++ )
temp.Add( kdata.ElementAt(i) );
//合并当日K线数据 by freeman
info.m_kdata.MergeKData( &temp );
}
else
//合并当日K线数据 by freeman
info.m_kdata.MergeKData( &kdata );
// 指数涨跌家数
int nSize = info.m_kdata.GetSize();
if( nSize > 0 )
{
info.m_dwAdvance = info.m_kdata.ElementAt(nSize-1).m_dwAdvance;
info.m_dwDecline = info.m_kdata.ElementAt(nSize-1).m_dwDecline;
}
}
container.UnLock();
return TRUE;
}
G:\tmp\stock\TskingVS2019\src\Client\StkLib\Src\SelfDB.cpp
//从乾隆文件中加载K线,合并5分钟K线数据 2019 / 06 / 08 by freeman
int CSelfDB::LoadKData(CStock* pstock, int nKType)
{
// WILLCHECK
int ret = CQianlong::LoadKData(pstock, nKType);
if (CKData::ktypeMin5 == nKType && LoadMinute(pstock) > 0)
{
CKData & kdataMin5 = pstock->GetKDataMin5();
CMinute & minute = pstock->GetMinute();
CKData kdataNew;
//分时线转K线
if (minute.ToKData(kdataNew) && CKData::ktypeMin5 == kdataNew.GetKType())
{
//合并5分钟K先数据
kdataMin5.MergeKData(&kdataNew);
}
return kdataMin5.GetSize();
}
return ret;
}
G:\stock\TskingVS2019\src\Client\StkLib\Src\Database.cpp
//加载K线数据时,依次枚举调用各个驱动获取K线数据
int CStDatabase::LoadKData( CStock *pstock, int period )
{
if( !pstock || !IsOK()) return 0;
int nSize = m_pStore->LoadKData( pstock, period );
for( int i=0; i<m_aptrAssistant.GetSize(); i++ )
{
IStStore * pStore = (IStStore *)m_aptrAssistant.ElementAt(i);
CStock stock;
stock.SetStockInfo( &(pstock->GetStockInfo()) );
if( pStore->LoadKData( &stock, period ) > 0 )
{
//从不同的数据提供接口中合并K线数据 ,这里需要性能优化 by freeman
nSize = pstock->MergeKData( stock, period );
}
}
return nSize;
}
接收到的分笔数据处理
// 刷新数据
BOOL bNeedReSort = FALSE;
for (DWORD i = 0; i < pCommPacket->m_dwCount; i++)
{
int id = 0;//股票在容器中的id号
if (container.GetStockInfo(pCommPacket->m_pReport[i].m_szCode, NULL, &id))
{
CStockInfo& info = container.ElementAt(id);//取得股票信息
UpdateStockInfoByREPORT(info, &(pCommPacket->m_pReport[i]));//更新成交明细数据
StockInfoChanged(id, info);//更新股票容器数据,id为股票在容器中的id号,info 为新的股票信息
bNeedReSort = TRUE;
}
}