首先聲明,鄙人是編程人員,不是股民。對選股概念瞭解甚少。本文僅做編程人員學習借鑑之用。不對選股理論進行探討和解釋。html
之前有客戶找我作過通達信插件選股的小任務,當時第一次接觸面向接口(此類「接口」)編程,也是第一次接觸到股票裏相關的概念。最近因爲接手一個任務,與上次開發相相似,故舊事重提,仔細研究一番。將我的學習研究所得知識與你們分享。在網上搜相關資料,可用的、有價值的甚少。但願此文能給將要研究通達信插件選股的編程人員一點點幫助。算法
編程環境:Viusal Studio 2010編程
證券終端:廣發證券至強版v6.06api
1、首先說一下在VS2010下,調試DLL的方法:函數
1,將Debug目錄下的dll(例如:MyPlugin.dll)文件複製到通達信根目錄下的plugin文件夾下,此步驟能夠手動,不過既然是開發程序,確定要調試N遍,會輸出N次dll文件,咱們能夠在VS寫個後期生成事件,例如:copy "C:Documents and SettingsAdministrator桌面choice2Debugchoice2.dll" D:通達信pluginchoice2.dll。此步設置以下圖。 學習
2,設置附加進程所在目錄,以下圖。url
通過以上設置,便可調試咱們開發的dll,監視變量的值。編譯成功後,設置斷點,啓動調試,而後操做通達信進行選股,選股開始即會跳到VS調試界面。
2、通達信官方提供的插件選股例子解析。(網上能夠下載到)
接口文檔裏,已經清楚的寫出了接口函數的相關說明。可是某些概念依然模糊,說一下個人理解。spa
1,必須足夠了解的幾個導出函數:插件
RegisterDataInterface 註冊回調函數,也就是PDATAIOFUNC,這個回調函數用來申請歷史數據調試
GetCopyRightInfo 填寫插件信息的函數,很easy
InputInfoThenCalc1 默認調用此函數,使用所有本地歷史數據
InputInfoThenCalc2 指定日期段的時候,調用此函數進行選股
2,必須足夠清楚的內容:
示例程序裏的m_pfn(Code,nSetCode,DataType,pHisDat,nDataNum,tmpTime,tmpTime,nTQ,0)函數,其中很是重要的參數是DataType,pHisDat,nDataNum。分別表示:想要申請的數據類型,數據存儲緩衝區(內存),想要獲取數據的個數上限(實際上獲得的極可能沒有那麼多),此函數的返回值就是實際上獲取到的數據個數。
InputInfoThenCalc1(char * Code,short nSetCode,int Value[4],short DataType,short nDataNum,BYTE nTQ,unsigned long unused) 如下講解中,以所有本地歷史數據爲例,即選股調用此函數
InputInfoThenCalc2(char * Code,short nSetCode,int Value[4],short DataType,NTime time1,NTime time2,BYTE nTQ,unsigned long unused)
經過下斷點監視,獲得結論:1.插件選股過程,針對每支股票調用一次InputInfoThenCalc1函數,若是返回值爲TRUE,表示該股票被選中,反之,不被選中。2.插件選股最多支持四個參數,四個參數的值,在插件的代碼裏用Value[4]來存儲。3.當我用日線數據獲取數據時,nDataNum被賦值爲2000,這個數據個數上限,基本足夠咱們編寫簡單的選股程序所用。
3、選出漲幅大於指定值的股票例子
BOOL InputInfoThenCalc1(char * Code,short nSetCode,int Value[4],short DataType,short nDataNum,BYTE nTQ,unsigned long unused) //按最近數據計算
{
BOOL nRet = FALSE;
NTime tmpTime;
memset(&tmpTime,0,sizeof(NTime)); //時間結構置爲0,獲取所有本地歷史數據
LPREPORTDAT pReport = new REPORTDAT;
if(m_pfn(Code,nSetCode,REPORT_DAT,pReport,1,tmpTime,tmpTime,0,0) == 1)
{
if(pReport->Close > 0.001 && (100*(pReport->Now-pReport->Close)/pReport->Close) > Value[0])
nRet = TRUE;
}
delete pReport;
return nRet;
}
特別注意:計算漲幅時,要使用行情數據,因此將數據類型指定爲REPORT_DAT,返回數據個數上限指定爲1便可,由於咱們只用當前的數據就夠了。漲幅的計算公式,百度一堆一堆。相對來講,這個是最簡單的。很容易理解。
4、選出換手率在指定範圍以內的股票
BOOL InputInfoThenCalc1(char * Code,short nSetCode,int Value[4],short DataType,short nDataNum,BYTE nTQ,unsigned long unused) //按最近數據計算
{
BOOL nRet = FALSE;
NTime tmpTime;
memset(&tmpTime,0,sizeof(NTime));
LPREPORTDAT pReport = new REPORTDAT;
long readnum = m_pfn(Code,nSetCode,REPORT_DAT,pReport,1,tmpTime,tmpTime,0,0);
LPSTOCKINFO pStockInfo = new STOCKINFO;
long readnum1 = m_pfn(Code,nSetCode,STKINFO_DAT,pStockInfo,1,tmpTime,tmpTime,0,0);
float HuanShou = ( pReport->Volume / pStockInfo->ActiveCapital ) * 10000;
if( HuanShou > Value[0] && HuanShou < Value[1] )
{
nRet = TRUE;
}
//delete pReportDat;
delete pStockInfo;
delete pReport;
return nRet;
}
換手率=某一段時期內的成交量/發行總股數×100% (在我國:成交量/流通總股數×100%)(引用百度百科)
按照上面的公式來計算,而後根據咱們須要的小數點位置來計算擴大或縮小的比例便可。同上例,咱們必定要注意咱們想要的數據,要指定的數據類型。計算換手率,須要成交量和總股數兩個數據,成交量使用當前的值,因此咱們獲取一個當前的便可,數據類型指定爲REPORT_DAT行情數據;總股數我並不知道是屬於哪一個數據類型的,一遍一遍嘗試改變數據類型以後,終於獲得了一個準確的值,此時,數據類型指定爲STKINFO_DAT。(有時候,咱們對幾種可能不是很瞭解的時候,能夠一個一個去嘗試,前提是,咱們要知道正確的結果是什麼樣的。一個辦法就是,先記錄下通達信界面上顯示的該數據的值)。
原本是打算順便計算一下量比數據的,也指定個範圍進行選股。通過嘗試後,發現通達信的接口貌似有問題。獲取成交量的時候,只能利用行情數據來獲取當前的成交量,沒法獲取歷史成交量。查閱資料:量比=現成交總手/〖(過去5個交易日平均每分鐘成交量)×當日累計開市時間(分)〗。(摘自百度百科)按照以上公式,咱們須要獲取到今日止連續6天的成交量。因此獲得以下代碼:
LPREPORTDAT pReportDat = new REPORTDAT[nDataNum];
long readnum2 = m_pfn(Code,nSetCode,DataType,pReportDat,nDataNum,tmpTime,tmpTime,0,0);
float * VolPoint= new float[readnum2];
for(int i=0;i < readnum2;i++)
{
VolPoint[i]=pReportDat[i].Volume;
}
float VolPerDay = VolPoint[readnum2-2]+VolPoint[readnum2-3]+VolPoint[readnum2-4]+VolPoint[readnum2-5]+VolPoint[readnum2-6];
float liangbi = VolPoint[readnum2-1] / (VolPerDay/5);
仔細分析,也許您會發現,代碼表達的意思,並非查閱資料所給出的公式。是的,若是按照公式來算,咱們應該獲得天天的,每分鐘的成交量數據,才能算出分鐘平均值。這樣的狀況,咱們就不能使用日線數據。就須要下載分時圖數據,按照標準的公式計算,保證您不會出錯。可是這裏,我仔細觀察計算獲得,以上代碼計算方法獲得的數據和通達信界面上顯示的量比是相吻合的。
重點指出:以上計算量比的代碼,並不能正常工做。由於歷史成交量沒法獲取,我嘗試過各類數據類型。當我獲取歷史成交量時,Volume字段的值都是莫名其妙的數字。可是更奇怪的是,其餘字段的值都正常。琢磨了很久,去了通達信官網論壇,發現一個帖子和我所遇到的問題同樣。帖子地址http://tdx.com.cn/dispbbs.asp?boardid=15&Id=173264 嘗試過各類結構體和數據類型組合後。我以爲以上求量比的代碼應該沒有問題。結果以下圖所示:
在這種狀況下,勉強利用了行情數據獲得了當前成交量,才得以計算出換手率。
5、計算CLOSE的EMA進行選股
//選股函數,參照官方例子程序+百度EMA算法得出以下代碼
BOOL InputInfoThenCalc1(char * Code,short nSetCode,int Value[4],short DataType,short nDataNum,BYTE nTQ,unsigned long unused) //按最近數據計算
{
BOOL nRet = FALSE;
NTime tmpTime={0};
LPHISDAT pHisDat = new HISDAT[nDataNum]; //數據緩衝區
long readnum = m_pfn(Code,nSetCode,DataType,pHisDat,nDataNum,tmpTime,tmpTime,nTQ,0); //利用回調函數申請數據,返回獲得的數據個數
if( readnum > max(Value[0],Value[1]) )
{
float *pMa1 = new float[readnum];
float *pMa2 = new float[readnum];
for(int i=0;i < readnum;i++)
{
pMa1[i] = pHisDat[i].Close;
pMa2[i] = pHisDat[i].Close;
}
float *EmaPoint1 = new float[readnum-Value[0]+1];
float *EmaPoint2 = new float[readnum-Value[1]+1];
memset( EmaPoint1 , 0 , readnum-Value[0]+1 );
memset( EmaPoint2 , 0 , readnum-Value[1]+1 );
AfxCalcEma( pMa1 , readnum , Value[0] , EmaPoint1);
AfxCalcEma( pMa2 , readnum , Value[1] , EmaPoint2);
if( AfxCross( EmaPoint1 , readnum-Value[0]+1 , EmaPoint2 , readnum-Value[1]+1 , Value[2] ) == 1 )
{
nRet = TRUE;
}
delete []EmaPoint1;EmaPoint1=NULL;
delete []EmaPoint2;EmaPoint2=NULL;
delete []pMa1;pMa1=NULL;
delete []pMa2;pMa2=NULL;
}
delete []pHisDat;pHisDat=NULL;
return nRet;
}
//計算CLOSE的EMA函數實現以下
void AfxCalcEma(float *pData , int nDataNum , int nDays , float *EmaPoint)
{
int nSumOfDays = 0;
int flag = 0;
int iCount =0;
for(iCount=nDays;iCount>0;iCount--)
{
nSumOfDays+=iCount;
}
for(iCount=nDays;iCount>0;iCount--)
{
float temp = (iCount/(float)nSumOfDays)*pData[iCount-1];
EmaPoint[0] += temp;
}
for(iCount = 1 , flag = nDays; iCount<nDataNum-nDays+1; iCount++ , flag++)
{
EmaPoint[iCount] = (2*pData[flag]+(nDays-1)*EmaPoint[iCount-1])/(nDays+1);
}
}
//計算指定之間範圍內,短線是否從下方穿越長線
int AfxCross( float *pMaPoint1 , int DataNum1 , float *pMaPoint2 , int DataNum2 , int nDaysNum )
{
int flag1 = DataNum1-1;
int flag2 = DataNum2-1;
if( pMaPoint1[flag1] > pMaPoint2[flag2] )
{
flag1--;
flag2--;
for(int iCount = nDaysNum; iCount>0; iCount--)
{
if( pMaPoint1[flag1] < pMaPoint2[flag2] )
{
return 1;
break;
}
else
{
flag1--;
flag2--;
}
}
}
else
{
return 0;
}
}
此例相對比較複雜,不過複雜的地方是算法部分,並非程序技術,主要是數學方面的知識。您有好的選股理念,在某種狀況下,是能夠用通達信插件選股的方式實現的。
結束語:謹以此文,獻給打算研究、正在研究和曾經研究過通達信插件選股的朋友們。這只是編程裏的冰山一角。但願咱們都能作一個優秀的開發人員,編寫出高質量的程序。處女做,你們多多批評指正。