📄 stockgraph.cpp
字号:
void CStockGraph::DrawNoDataInfo( CDC * pDC )
{
DECLARE_COLOR_DEFINATION
CKData & kdata = m_CurStock.GetKData(m_nCurKType);
if( 0 == kdata.GetSize() )
{
CString strNoKData = "无历史数据", strTemp;
strTemp = CString(m_CurStock.GetStockInfo().GetStockName()) + "(" + m_CurStock.GetStockInfo().GetStockCode() + ")";
strTemp += (LPCTSTR)AfxGetKTypeString( m_nCurKType );
strNoKData = strTemp + strNoKData;
pDC->SetBkColor( clrBK );
pDC->SetTextColor( clrTitle );
pDC->TextOut( m_rectAll.left+20, m_rectAll.top+20, strNoKData );
}
}
void CStockGraph::DrawDateAxis( CDC * pDC )
{
CHECK_NODATATODRAW
DECLARE_COLOR_DEFINATION
CRect rect = m_rectCenter;
rect.top = m_rectAll.bottom - m_nMarginBottom + 1;
pDC->FillSolidRect( &rect, clrBK );
pDC->SetBkColor( clrBK );
pDC->SetTextColor( clrDJ );
CKData & kdata = m_CurStock.GetKData( m_nCurKType );
BOOL bDayOrMin = CKData::IsDayOrMin(m_nCurKType);
int y = m_rectAll.bottom - m_nMarginBottom + 2;
int xLast = 0;
for( int k=m_nIndexStart; k<=m_nIndexEnd; k++ )
{
if( k > 0 && k < kdata.GetSize() )
{
CSPTime sptimeLast, sptime;
if( sptimeLast.FromStockTime( kdata.ElementAt(k-1).m_date, bDayOrMin )
&& sptime.FromStockTime( kdata.ElementAt(k).m_date, bDayOrMin ) )
{
CString strText;
if( (CKData::ktypeDay == m_nCurKType )
&& (sptimeLast.GetMonth() != sptime.GetMonth()) )
strText = sptime.Format( "%m" );
else if( (CKData::ktypeWeek == m_nCurKType || CKData::ktypeMonth == m_nCurKType)
&& (sptimeLast.GetYear() != sptime.GetYear()) )
strText = sptime.Format( "%y" );
else if( !CKData::IsDayOrMin(m_nCurKType)
&& (sptimeLast.GetDay() != sptime.GetDay()) )
strText = sptime.Format( "%d" );
CRect rectK;
if( strText.GetLength() > 0 && GetOneKLineRect( k, &rectK, NULL, NULL, NULL ) && xLast < rectK.left )
{
pDC->TextOut( rectK.left, y, strText );
xLast = rectK.left + pDC->GetTextExtent(strText).cx;
}
}
}
}
}
void CStockGraph::DrawKLine(CDC * pDC )
{
DECLARE_COLOR_DEFINATION
CKData & kdata = m_CurStock.GetKData(m_nCurKType);
pDC->FillSolidRect( &m_rectKLine, clrBK );
pDC->Draw3dRect( &m_rectKLine, clrBorder, clrBorder );
// Draw Title
CString strTitle;
pDC->SetTextColor( clrTitle );
pDC->SetBkColor( clrBK );
strTitle = AfxGetKTypeString( m_nCurKType );
pDC->TextOut( m_rectAll.left+8, m_rectAll.top+2, strTitle );
strTitle = "K 线";
pDC->TextOut( m_rectKLine.left+1, m_rectAll.top+2, strTitle );
double dMin = 0, dMax = 0;
if( ! GetKLineMinMaxInfo( m_nIndexStart, m_nIndexEnd, &dMin, &dMax ) )
return;
m_dMaxPrice = dMax;
m_dMinPrice = dMin;
// Draw Axis
DrawAxis( pDC, m_rectKLine, m_nHeightSubtitle, 3, dMin, dMax, TRUE, TRUE, 2 );
// KLine Attribute Rect
CRect rectKLineAttrib = m_rectKLineCenter;
rectKLineAttrib.top -= m_nHeightSubtitle;
int k;
// Draw STT_DJ and STT_CW
CSPDWordArray & anTech = AfxGetProfile().GetGraphTechsKLine( );
for( k=0; k<anTech.GetSize(); k++ )
if( STT_DJ == anTech[k] || STT_CW == anTech[k] )
DrawKLineAttribute( pDC, anTech[k], rectKLineAttrib, FALSE, dMin, dMax );
// Draw K Line
for( k=m_nIndexStart; k<=m_nIndexEnd; k++ )
{
DrawOneKLine( pDC, k, k, &kdata, dMin, dMax, FALSE );
}
// Draw Tech KLine except STT_DJ and STT_CW
for( k=0; k<anTech.GetSize(); k++ )
if( STT_DJ != anTech[k] && STT_CW != anTech[k] )
DrawKLineAttribute( pDC, anTech[k], rectKLineAttrib, FALSE, dMin, dMax );
if( anTech.GetSize() > 0 )
DrawKLineAttribute( pDC, anTech[0], rectKLineAttrib, TRUE, dMin, dMax );
// Draw Select Line
DrawSelectionLine( pDC, TRUE );
}
BOOL CStockGraph::GetKLineMinMaxInfo( int nStart, int nEnd, double * pdMin, double * pdMax )
{
CKData & kdata = m_CurStock.GetKData(m_nCurKType);
CKLine kline( &kdata );
double dMin = 0, dMax = 0, dMinTemp = 0, dMaxTemp = 0;
if( nStart < 0 || nEnd < 0 || ! kline.GetMinMaxInfo( nStart, nEnd, &dMin, &dMax ) )
return FALSE;
CSPDWordArray & anTech = AfxGetProfile().GetGraphTechsKLine( );
for( int k=0; k<anTech.GetSize(); k++ )
{
UINT nTech = anTech[k];
switch( nTech )
{
case STT_MA:
{
CMA ma( &kdata );
if( ma.GetMinMaxInfo( nStart, nEnd, &dMinTemp, &dMaxTemp ) )
{
if( dMinTemp < dMin ) dMin = dMinTemp;
if( dMaxTemp > dMax ) dMax = dMaxTemp;
}
}
break;
case STT_BBI:
{
CBBI bbi( &kdata );
if( bbi.GetMinMaxInfo( nStart, nEnd, &dMinTemp, &dMaxTemp ) )
{
if( dMinTemp < dMin ) dMin = dMinTemp;
if( dMaxTemp > dMax ) dMax = dMaxTemp;
}
}
break;
case STT_BOLL:
{
CBOLL boll( &kdata );
if( boll.GetMinMaxInfo( nStart, nEnd, &dMinTemp, &dMaxTemp ) )
{
if( dMinTemp < dMin ) dMin = dMinTemp;
if( dMaxTemp > dMax ) dMax = dMaxTemp;
}
}
break;
case STT_PV:
{
CPV pv( &kdata );
if( pv.GetMinMaxInfo( nStart, nEnd, &dMinTemp, &dMaxTemp ) )
{
if( dMinTemp < dMin ) dMin = dMinTemp;
if( dMaxTemp > dMax ) dMax = dMaxTemp;
}
}
break;
case STT_SAR:
{
CSAR sar( &kdata );
if( sar.GetMinMaxInfo( nStart, nEnd, &dMinTemp, &dMaxTemp ) )
{
if( dMinTemp < dMin ) dMin = dMinTemp;
if( dMaxTemp > dMax ) dMax = dMaxTemp;
}
}
break;
case STT_DJ:
case STT_CW:
break;
default:;
ASSERT( FALSE );
}
}
if( pdMin )
*pdMin = dMin;
if( pdMax )
*pdMax = dMax;
return TRUE;
}
void CStockGraph::DrawOneKLine(CDC * pDC, int nIndexPos, int nIndexKD, CKData * pKData, double dMin, double dMax, BOOL bGreyed )
{
DECLARE_COLOR_DEFINATION
// Check Valid
ASSERT( pDC && nIndexPos >= m_nIndexStart && nIndexPos <= m_nIndexEnd && nIndexPos >= 0 );
if( !(pDC && nIndexPos >= m_nIndexStart && nIndexPos <= m_nIndexEnd && nIndexPos >= 0) )
return;
if( !pKData || nIndexKD < 0 || nIndexKD >= pKData->GetSize() )
return;
if( dMax-dMin < 1e-4 )
return;
// Get Region
CRect rectK, rcEntity;
long xMedium = 0;
if( !GetOneKLineRect( nIndexPos, &rectK, &rcEntity.left, &rcEntity.right, &xMedium ) )
return;
int xStart = rectK.left;
int xEnd = rectK.right;
ASSERT( xEnd <= m_rectKLineCenter.right );
if( xEnd > m_rectKLineCenter.right )
return;
KDATA kd = pKData->ElementAt(nIndexKD);
// Set rcEntity's top and bottom, set yLow, yHigh
int yLow = int( m_rectKLineCenter.bottom - m_rectKLineCenter.Height() * (kd.m_fLow - dMin) / (dMax-dMin) );
int yHigh = int( m_rectKLineCenter.bottom - m_rectKLineCenter.Height() * (kd.m_fHigh - dMin) / (dMax-dMin) );
int yOpen = int( m_rectKLineCenter.bottom - m_rectKLineCenter.Height() * (kd.m_fOpen - dMin) / (dMax-dMin) );
int yClose = int( m_rectKLineCenter.bottom - m_rectKLineCenter.Height() * (kd.m_fClose - dMin) / (dMax-dMin) );
rcEntity.top = min( yOpen, yClose );
rcEntity.bottom = max( yOpen, yClose ) + 1;
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
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 );
}
else if( CStockGraph::klineAmerica == m_nCurKLineMode )
{
// Draw Entity
COLORREF clr = clrRise;
if( kd.m_date > m_dwLatestDate )
clr = clrNewKLine;
if( bGreyed )
clr = clrDJ;
pDC->SetBkColor( clrBK );
// Draw Line
CPen pen( PS_SOLID, 1, clr );
CPen *pOldPen = pDC->SelectObject( &pen );
pDC->MoveTo( xStart, yHigh );
pDC->LineTo( xStart, yLow );
pDC->MoveTo( xStart, yClose );
pDC->LineTo( xEnd, yClose );
pDC->SelectObject( pOldPen );
}
else if( CStockGraph::klineTower == 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 );
if( nIndexKD > 0 )
{
KDATA kdLast = pKData->ElementAt(nIndexKD-1);
int yOpenLast = int( m_rectKLineCenter.bottom - m_rectKLineCenter.Height() * (kdLast.m_fOpen - dMin) / (dMax-dMin) );
int yCloseLast = int( m_rectKLineCenter.bottom - m_rectKLineCenter.Height() * (kdLast.m_fClose - dMin) / (dMax-dMin) );
if( kdLast.m_fClose > kdLast.m_fOpen && kd.m_fClose < kd.m_fOpen )
{
rcEntity.bottom = min(yOpenLast,rcEntity.bottom);
if( rcEntity.bottom > rcEntity.top )
{
pDC->FillSolidRect( &rcEntity, clrBK );
clr = clrRise;
if( kd.m_date > m_dwLatestDate )
clr = clrNewKLine;
if( bGreyed )
clr = clrDJ;
pDC->Draw3dRect( &rcEntity, clr, clr );
}
}
else if( kdLast.m_fClose < kdLast.m_fOpen && kd.m_fClose > kd.m_fOpen )
{
rcEntity.top = max(yOpenLast,rcEntity.top);
if( rcEntity.bottom > rcEntity.top )
{
clr = clrFallEntity;
if( kd.m_date > m_dwLatestDate )
clr = clrNewKLine;
if( bGreyed )
clr = clrDJ;
pDC->FillSolidRect( &rcEntity, clr );
}
}
}
}
}
void CStockGraph::DrawBorderMovingLine( CDC * pDC, CPoint point, BOOL bAddOrRemove )
{
ASSERT( m_pParent && ::IsWindow( m_pParent->GetSafeHwnd() ) );
if( !m_pParent || !::IsWindow(m_pParent->GetSafeHwnd()) )
return;
CClientDC dc(m_pParent);
if( NULL == pDC )
pDC = &dc;
CPen penLine( PS_SOLID, 1, AfxGetProfile().GetColor( CColorClass::clrBorder ) );
CPen * pOldPen = pDC->SelectObject( &penLine );
int nOldDrawMode = pDC->SetROP2( R2_XORPEN );
pDC->MoveTo( m_rectKLine.left-5, point.y );
pDC->LineTo( m_rectKLine.right+5, point.y );
pDC->SetROP2( nOldDrawMode );
pDC->SelectObject( pOldPen );
}
void CStockGraph::DrawSelectionLine( CDC * pDC, BOOL bAddOrRemove )
{
ASSERT( m_pParent && ::IsWindow( m_pParent->GetSafeHwnd() ) );
if( !m_pParent || !::IsWindow(m_pParent->GetSafeHwnd()) )
return;
CClientDC dc(m_pParent);
if( NULL == pDC )
pDC = &dc;
CPen penVLine( PS_SOLID, 1, AfxGetProfile().GetColor( CColorClass::clrLine1 ) );
CPen * pOldPen = pDC->SelectObject( &penVLine );
int nOldDrawMode = pDC->SetROP2( R2_XORPEN );
CRect rectK;
long xMedium = 0;
if( GetOneKLineRect( m_nIndexCurrent, &rectK, NULL, NULL, &xMedium ) )
{
pDC->MoveTo( xMedium, m_rectCenter.bottom );
pDC->LineTo( xMedium, m_rectKLineCenter.top );
}
for( int k=0; k<m_anIndexCurrent.GetSize(); k++ )
{
if( ((int)m_anIndexCurrent[k]) == m_nIndexCurrent )
continue;
if( GetOneKLineRect( m_anIndexCurrent[k], &rectK, NULL, NULL, &xMedium ) )
{
pDC->MoveTo( xMedium, m_rectKLineCenter.bottom );
pDC->LineTo( xMedium, m_rectKLineCenter.top );
}
}
pDC->SetROP2( nOldDrawMode );
pDC->SelectObject( pOldPen );
}
void CStockGraph::DrawSelectionRect( CDC * pDC, CPoint ptBegin, CPoint ptEnd, BOOL bAddOrRemove )
{
ASSERT( m_pParent && ::IsWindow( m_pParent->GetSafeHwnd() ) );
if( !m_pParent || !::IsWindow(m_pParent->GetSafeHwnd()) )
return;
CClientDC dc(m_pParent);
if( NULL == pDC )
pDC = &dc;
CPen penVLine( PS_SOLID, 1, AfxGetProfile().GetColor( CColorClass::clrLine2 ) );
CPen * pOldPen = pDC->SelectObject( &penVLine );
int nOldDrawMode = pDC->SetROP2( R2_XORPEN );
CRect rect;
rect.left = min(ptBegin.x,ptEnd.x);
rect.right = max(ptBegin.x,ptEnd.x);
rect.top = min(ptBegin.y,ptEnd.y);
rect.bottom = max(ptBegin.y,ptEnd.y);
pDC->MoveTo( rect.left, rect.top );
pDC->LineTo( rect.right, rect.top );
pDC->LineTo( rect.right, rect.bottom );
pDC->LineTo( rect.left, rect.bottom );
pDC->LineTo( rect.left, rect.top );
pDC->SetROP2( nOldDrawMode );
pDC->SelectObject( pOldPen );
}
void CStockGraph::DrawKData( )
{
if( !::IsWindow( m_wndKData.GetSafeHwnd() ) )
{
if( !m_wndKData.Create( NULL, "", WS_CHILD, m_rectKData, m_pParent, 0 ) )
{
TRACE( "Failed to create m_wndKData!\n" );
return;
}
m_wndKData.SetWindowPos( NULL, m_rectKData.left, m_rectKData.top, m_rectKData.Width(), m_rectKData.Height(),
SWP_SHOWWINDOW );
}
CClientDC dc(&m_wndKData);
CRect rectClient;
m_wndKData.GetClientRect( &rectClient );
CKData &kdata = m_CurStock.GetKData(m_nCurKType);
if( m_nIndexCurrent >= 0 && m_nIndexCurrent < kdata.GetSize() )
{
m_wndKData.SetWindowPos( NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW );
m_wndKData.ValidateRect( &rectClient );
DrawKData( &dc, rectClient );
m_wndKData.ValidateRect( &rectClient );
}
else
m_wndKData.SetWindowPos( NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_HIDEWINDOW );
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -