策略为王源代码扩展系列-技术指标-增加成交笔数指标

Published

第一部分 建立技术指标类

step 1:新建一个指标类CHSL()

G:\stock\TskingVS2019\src\Client\StkLib\Include\Technique.h


///	相对换手率HSL2
class STKLIB_API CHSL2 : public CTechnique
{
public:
	// Constructors
	CHSL2();
	CHSL2(CKData* pKData);
	virtual ~CHSL2();

	static	double GetMainChangeHand(DWORD dwMarket, CKData& kdata, int nIndexKD);

public:
	virtual	void Clear();

	CStockInfo	m_stockinfo;

	// Attributes
	int		m_nDays;	// Not Used
	int		m_nMADays;	// Not Used
	int		m_itsGoldenFork;	// Not Used
	int		m_itsDeadFork;		// Not used
	virtual	void	SetDefaultParameters();
	void	AttachParameters(CHSL2& src);
	virtual	BOOL	IsValidParameters();

	// Operations
	virtual	int		GetSignal(int nIndex, UINT* pnCode = NULL);
	virtual	BOOL	GetMinMaxInfo(int nStart, int nEnd, double* pdMin, double* pdMax);
	virtual	BOOL	Calculate(double* pValue, int nIndex, BOOL bUseLast);
	virtual	BOOL	Calculate(double* pValue, int nIndex, int nDays, BOOL bUseLast);
};

 

策略为王类,加实现。不同类的实现放在不同文件中,本类为策略为王类,在TechCLK.cpp实现

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


//////////////////////////////////////////////////////////////////////
//	CHSL2
CHSL2::CHSL2()
{
	SetDefaultParameters();
}

CHSL2::CHSL2(CKData* pKData)
	: CTechnique(pKData)
{
	SetDefaultParameters();
}

CHSL2::~CHSL2()
{
	Clear();
}

double CHSL2::GetMainChangeHand(DWORD dwMarket, CKData& kdata, int nIndexKD)
{
	if (nIndexKD < 0 || nIndexKD >= kdata.GetSize())
		return 0.0;

	KDATA	kd = kdata.ElementAt(nIndexKD);

	// ignore dwMarket
	dwMarket = CStock::marketSHSE;

	CStock& stockMain = AfxGetStockMain(dwMarket);
	CStockInfo& infoMain = stockMain.GetStockInfo();
	CKData& kdataMain = stockMain.GetKData(kdata.GetKType());
	int nIndexMain = kdataMain.GetIndexByDate(kd.m_date);
	if (nIndexMain < 0 || nIndexMain >= kdataMain.GetSize())
		return 0.0;
	KDATA kdMain = kdataMain.ElementAt(nIndexMain);

	double	dPriceAvg = 0.0;
	if (kdMain.m_fVolume > 1)
		dPriceAvg = kdMain.m_fAmount / kdMain.m_fVolume;

	double	dCapitalValue = 0.0;
	if (0 == strcmp(STKLIB_CODE_MAIN, infoMain.GetStockCode()))
	{
		double	dFactor = 5.85 * 1e8;
		CSPTime	sptime;
		if (sptime.FromStockTime(kd.m_date, CKData::IsDayOrMin(kdata.GetKType())))
		{
			CSPTime	tm0(2004, 5, 19, 0, 0, 0);
			CSPTimeSpan	span = sptime - tm0;

			if (span.GetDays() < -3000)
			{
				dFactor *= (1 - 0.08 * 3000.0 / 365.0);
				dFactor *= (1 - (-3000 - span.GetDays()) / 2000.0);
			}
			else
			{
				dFactor *= (1 + 0.08 * span.GetDays() / 365.0);
			}
		}
		dCapitalValue = dFactor * (kdMain.m_fClose + kdMain.m_fOpen + kdMain.m_fHigh + kdMain.m_fLow) / 4;
	}
	else if (0 == strcmp(STKLIB_CODE_MAINSZN, infoMain.GetStockCode()))
	{
		// 深证成指
		dCapitalValue = 0.41 * 1e8 * (kdMain.m_fClose + kdMain.m_fOpen + kdMain.m_fHigh + kdMain.m_fLow) / 4;
	}

	double dChangeHand = 0.0;
	if (dCapitalValue > 1e-6)
		dChangeHand = 100. * kdMain.m_fAmount / dCapitalValue;

	return dChangeHand;
}

void CHSL2::SetDefaultParameters()
{
	m_nDays = 30;
	m_nMADays = 6;
	m_itsGoldenFork = ITS_BUY;
	m_itsDeadFork = ITS_SELL;
}

void CHSL2::AttachParameters(CHSL2& src)
{
	m_nDays = src.m_nDays;
	m_nMADays = src.m_nMADays;
	m_itsGoldenFork = src.m_itsGoldenFork;
	m_itsDeadFork = src.m_itsDeadFork;
}

BOOL CHSL2::IsValidParameters()
{
	return (VALID_DAYS(m_nDays) && VALID_DAYS(m_nMADays) && VALID_ITS(m_itsGoldenFork) && VALID_ITS(m_itsDeadFork));
}

void CHSL2::Clear()
{
	CTechnique::Clear();
}

int CHSL2::GetSignal(int nIndex, UINT* pnCode)
{
	if (pnCode)* pnCode = ITSC_NOTHING;
	return ITS_NOTHING;
}

BOOL CHSL2::GetMinMaxInfo(int nStart, int nEnd,
	double* pdMin, double* pdMax)
{
	return AfxGetMinMaxInfo1(nStart, nEnd, pdMin, pdMax, this);
}

/***
	相对换手率
*/
BOOL CHSL2::Calculate(double* pValue, int nIndex, BOOL bUseLast)
{
	STT_ASSERT_CALCULATE1(m_pKData, nIndex);

	if (LoadFromCache(nIndex, pValue))
		return TRUE;

	double	dRatioChangeHand = 0;
	double	dVolume = m_pKData->ElementAt(nIndex).m_fVolume;
	if (m_stockinfo.IsValidStock() && m_stockinfo.GetRatioChangeHand(&dRatioChangeHand, dVolume))
	{
		// 相对换手率
		double	dMainChangeHand = GetMainChangeHand(m_stockinfo.GetMarket(), *m_pKData, nIndex);
		double	dRelativeChangeHand = 1.0;
		if (dMainChangeHand > 1e-6)
		{
			dRelativeChangeHand = dRatioChangeHand / dMainChangeHand;
			if (pValue)
				* pValue = dRelativeChangeHand;
			StoreToCache(nIndex, pValue);
			return TRUE;
		}
	}
	else
	{
		if (pValue)
			* pValue = 1.0;
		StoreToCache(nIndex, pValue);
		return TRUE;
	}

	return FALSE;
}

 

第二部分 给该类定义编号和名称,即定义该类的ID、根据ID创建对象

2.1 定义编号

step 1.定义STT_HSL2的值,同时修改对应的大小值,程序会建立一个长度为STT_MAX大小的数组。

src/Client/StkLib/Include/Technique.h

 src/Client/StkLib/Include/Technique.h

#define	STT_DCYO		51		//	去噪周期摆动量DCYO
#define	STT_HSL			52		//	相对换手率HSL
#define	STT_DPER		53		//	去势百分比指标DPER
#define	STT_CLK_MAX		53

#define	STT_MAX			53
#define	STT_HSL2		54
#define	STT_CLK_MAX		54
#define	STT_MAX			54 

2.2 定义名称:用于显示类名称

原理:定义一个数组,存放该类的ID 和名称

src/Client/StkLib/Src/Strings.cpp

//////////////////////////////////////////////////////////////////////////////////
// 指标字符串

// 给定技术指标唯一编号,返回技术指标中文名称
CSPString	AfxGetSTTName(UINT nTech)
{
	static	CSPString	stt_names[STT_MAX + 1];
	SP_ASSERT(STT_MAX >= 0);

		/**** extend 扩展指标 by freeman ****/
		stt_names[STT_DJ2] = ("叠加图2");  //叠加图 名字定义 by freeman
		/**********************end***********/

 

定义该类的短名

// 给定技术指标唯一编号,返回技术指标英文简称
CSPString	AfxGetSTTShortName(UINT nTech)
{
	static	CSPString	stt_shortnames[STT_MAX + 1];
	SP_ASSERT(STT_MAX >= 0);

	if (stt_shortnames[0].GetLength() <= 0)
	{
		// stt_shortnames
		stt_shortnames[0] = "STTShortNames";

		/**** extend 扩展指标 by freeman ****/
		stt_shortnames[STT_DJ2] = ("DJ2");
		/**********************end***********/

至此,各种指标菜单可以看见HSL2指标了。

2.3 根据编号创建对象

 

 

step 3: 创建新的技术指标对象,并传入K线数据

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

// 创建新的技术指标对象
CTechnique * CTechnique::CreateTechnique( UINT nTech, CKData * pKData )
{
	CTechnique	*	pTech	=	NULL;
	switch( nTech )
	{
	case STT_DPER:		pTech	=	new CDPER( pKData );	break;


		case STT_HSL2:	pTech = new CHSL2(pKData);	break;

		default:
			SP_ASSERT( FALSE );
	}

 

step 3: 

src/Client/StkLib/Src/Profile.cpp

CTechParameters::FindParameters( UINT nTech, CTechnique * pTech )
		case STT_DCYO:		((CDCYO *)pTech)->AttachParameters( dcyo );		break;
		case STT_HSL:		((CHSL *)pTech)->AttachParameters( hsl );		break;
		case STT_DPER:		((CDPER *)pTech)->AttachParameters( dper );		break;
	/**** extend 扩展指标 by freeman ****/
		case STT_DJ2:		((CDJ2*)pTech)->AttachParameters(dj2);		break;
	/**********************end***********/

		default:
			SP_ASSERT( FALSE );

至此,该技术指标类可以被调用了

 

第三部分 建立CTechParameters 技术指标参数类

1.定义 CDJ2 类型变量

////////////////////////////////////////////////////////////////////////////
// CTechParameters
/***
	技术指标参数,包含所有技术指标的参数设定
*/
class STKLIB_API CTechParameters
{
public:
	CTechParameters( );

	void	Clear( );
	void	SetKData( CKData * pKData );
	void	SetDefaultParametersAll( );
	BOOL	FindParameters( UINT nTech, CTechnique * pTech );
	void	Serialize( CSPArchive &ar );

	CMA		ma;
/**** extend 扩展指标 by freeman ****/
	CDJ2		dj2;
	/**********************end***********/

 

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

//////////////////////////////////////////////////////////////////////
// CTechParameters
CTechParameters::CTechParameters( )
{
}

void CTechParameters::Clear( )
{
	ma.Clear( );

	/**** extend 扩展指标 by freeman ****/
	dj2.Clear();
	/**********************end***********/

void CTechParameters::SetKData( CKData * pKData )
{
	ma.SetKData( pKData );

	/**** extend 扩展指标 by freeman ****/
	dj2.SetKData(pKData);
	/**********************end***********/
}
void CTechParameters::SetDefaultParametersAll( )
{
	ma.SetDefaultParameters( );
	
	/**** extend 扩展指标 by freeman ****/
	dj2.SetDefaultParameters();
	/**********************end***********/
}

 

BOOL CTechParameters::FindParameters( UINT nTech, CTechnique * pTech )
{
	switch( nTech )
	{
		case STT_MA:		((CMA *)pTech)->AttachParameters( ma );		break;
/**** extend 扩展指标 by freeman ****/
		case STT_DJ2:		((CDJ2*)pTech)->AttachParameters(dj2);		break;
	/**********************end***********/

第四部分 画叠加图

 

step 2:添加画图函数

 src/Client/StkUI/View/StockGraph.h

/***
	画图类,负责画出技术指标视图中的所有部分
*/
class CStockGraph
{
public:
	CStockGraph( );
	virtual	~CStockGraph( );
	void		SetParent( CWnd * pParent );
	void		ResetMargins(	int nMarginTop = 19, int nMarginBottom = 18,
								int nHeightSubtitle = 15, int nWidthSubtitle = 70,
								int nWidthParameter = 100, int nDefaultThickness = 6 );
/**** extend 扩展指标 by freeman ****/
   //功能:画叠加图函数 CStockGraph::DrawTechDJ2()
	void        DrawTechDJ2(CDC* pDC, CRect rect, BOOL bDrawTitle, double dMin, double dMax);
	/**********************end***********/

 

 

实现

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

//功能:画叠加图函数 CStockGraph::DrawTechDJ2()
void CStockGraph::DrawTechDJ2(CDC* pDC, CRect rect, BOOL bDrawTitle, double dMin, double dMax)
{
	CHECK_NODATATODRAW
		DECLARE_COLOR_DEFINATION

	CKData& kdata = m_CurStock.GetKData(m_nCurKType);
	m_techparam.dj2.AttachParameters(AfxGetProfile().GetTechParameters().dj2);

	// Draw Sub Title
	if (bDrawTitle)
	{
		CString	strTitle = AfxGetSTTShortName(STT_DJ2);//叠加图
		strTitle += "    ";
		if (m_CurStock.GetStockInfo().IsShangHai())
			strTitle += m_techparam.dj2.m_strCodeSha;
		else if (m_CurStock.GetStockInfo().IsShenZhen())
			strTitle += m_techparam.dj2.m_strCodeSzn;
		DrawTechTitle(pDC, rect.left + 5, rect.top + 1, strTitle, TA_LEFT | TA_TOP, 14, clrBK, clrTitle);//bug.叠加图覆盖了均线指标的提示,未解决
		return;
	}

	// Prepare Data
	if (!m_techparam.dj2.IsValidParameters())
		m_techparam.dj2.SetDefaultParameters();
	if (!m_techparam.dj2.PrepareStockData(&AfxGetDB(), m_CurStock.GetStockCode(),
		m_nCurKType, m_nCurKFormat, m_nCurMaindataType,
		AfxGetProfile().GetAutoResumeDRBegin(), AfxGetProfile().GetAutoResumeDRLimit()))
		return;
	CKData* pKData = NULL;
	if (m_CurStock.GetStockInfo().IsShangHai())
		pKData = &(CDJ2::m_stockSha.GetKData(m_nCurKType));
	else if (m_CurStock.GetStockInfo().IsShenZhen())
		pKData = &(CDJ2::m_stockSzn.GetKData(m_nCurKType));
	else
		return;

	// GetMinMaxInfo
	double	dMinDJ = 0, dMaxDJ = 0;
	CKLine	kline(pKData);
	int	nStartDJ = pKData->GetIndexByDate(kdata.ElementAt(m_nIndexStart).m_date);
	int	nEndDJ = pKData->GetIndexByDate(kdata.ElementAt(m_nIndexEnd).m_date);
	if (-1 == nStartDJ)	nStartDJ = 0;
	if (-1 == nEndDJ)		nEndDJ = pKData->GetSize() - 1;
	if (nStartDJ < 0 || nEndDJ < 0 || !kline.GetMinMaxInfo(nStartDJ, nEndDJ, &dMinDJ, &dMaxDJ))
		return;

	// Draw
	for (int nIndex = m_nIndexStart; nIndex <= m_nIndexEnd; nIndex++)
	{
		DWORD	date = kdata.ElementAt(nIndex).m_date;
		int	nIndexDJ = pKData->GetIndexByDate(date);
		if (nIndexDJ >= 0 && nIndexDJ < pKData->GetSize())
		{
			DrawOneKLine(pDC, nIndex, nIndexDJ, pKData, dMinDJ, dMaxDJ, TRUE);
		}
	}
}

 

画叠加图

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

//画周期K线图 by freeman
void CStockGraph::DrawKLine(CDC* pDC)
{
DrawTechDJ2(pDC,  rectKLineAttrib, FALSE, dMin, dMax);
}

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

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:
		{
                 ....

                /**** extend 扩展指标 by freeman ****/
		case STT_DJ2:
        /**********************end***********/
		default:;
			ASSERT(FALSE);
		}
	}