第一部分 建立技术指标类
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);
}
}