人人爽天天爽夜夜爽qc-人人爽天天爽夜夜爽曰-人人天天爱天天做天天摸-人人天天夜夜-色网站在线-色网站在线看

您現在的位置:程序化交易>> 期貨公式>> 金字塔等>> 金字塔模型>>正文內容

[原創]教你寫一個金字塔不卡的復雜圖表策略[金字塔模型]

 

前言

這是一個代碼框架,其中部分靈感來自阿火的策略、guotx2010的VBA教程和王峰的一句話(如果你注重效率,那么金字塔提供的全局變量數據庫的速度完全可以超越INI文件的),所以在此向各位前輩致謝!

 

適用本框架的前提:

不使用金字塔規定不能用于if ... then中的函數(如統計函數、未來函數等)、采用走完K線、且K線走完后信號就固定下來的(即未來不會發生改變)、使用新圖表交易函數、勾選“僅刷最后一根K線”

 

步驟:

 

第一步:創建3個自定義函數,創建方法在此不詳述,VBA代碼如下:

\'定義4個動態數組保存信號和信號發生日期和時間

dim dates()
dim times()
dim values()
dim SigCounts()
SigCount = 0

 

Function INSERTSIG(Formula,SIGNUM,D,T,H)
 \'通過VBA數組記錄信號以及信號發生的時間,當最新信號發出時執行一次
 INSERTSIG=0
 On Error Resume Next
 dates(SIGNUM).AddBack(D)
 if err.number<>0 then
  INSERTSIG=1
  exit function
 end if
 times(SIGNUM).AddBack(T)
 values(SIGNUM).AddBack(H)
 if dates(SIGNUM).Count>SigCounts(SIGNUM) and SigCounts(SIGNUM)>0 then
  dates(SIGNUM).RemoveAt(0)
  times(SIGNUM).RemoveAt(0)
  values(SIGNUM).RemoveAt(0)
 end if
End Function

 

Function READSIG(Formula,SIGNUM)
    \'將數組信號發生時間轉換為K線位置,并記錄到單值全局變量系統中,供Perl公式讀取,每產生一次新K線時執行一次
 READSIG=0
 On Error Resume Next
 cc = times(SIGNUM).Count
 if err.number<>0 then
     READSIG = 1
     exit function
 end if
 iGlobal=document.ExtDataNum
 for i=iGlobal to 0 step -1
  iKeyValue=document.GetExtDataByIndex(i,sKeyName)
  if (strComp(left(sKeyName,5),"HH" & right(Formatnumber(1000+SIGNUM,0,0,0,0),3))=0) or (strComp(left(sKeyName,5),"PP" & right(Formatnumber(1000+SIGNUM,0,0,0,0),3))=0) then
   call document.RemoveExtData(i)
    end if
 next
 
 Set History = Formula.ParentGrid.GetHistoryData()
 next_sig_pos = 0
 For i = times(SIGNUM).Count-1 To 0 step -1
  str = Formatnumber(19000000+dates(SIGNUM).GetAt(i),0,0,0,0) & Formatnumber(1000000+times(SIGNUM).GetAt(i),0,0,0,0)
  str = mid(str,1,4) & "-" & mid(str,5,2) & "-" & mid(str,7,2)  & " " & mid(str,10,2) & ":" & mid(str,12,2) & ":" & mid(str,14,2)
  bi = History.GetPosFromDate(str) + 1
  Document.SetExtData "PP" & right(Formatnumber(1000+SIGNUM,0,0,0,0),3) & Formatnumber(bi,0,0,0,0),next_sig_pos
  Document.SetExtData "HH" & right(Formatnumber(1000+SIGNUM,0,0,0,0),3) & Formatnumber(bi,0,0,0,0),values(SIGNUM).GetAt(i)
  next_sig_pos = bi
 Next
 Document.SetExtData "PP" & right(Formatnumber(1000+SIGNUM,0,0,0,0),3) & "1",next_sig_pos
End Function

 

Function INIT_SIG(Formula,SigNum,Count)
    \'初始化數組,加載公式時或其他必要時間(例如加載新品種時)運行一次
 INIT_SIG=0
 On Error Resume Next
 Set dates(SigNum) = nothing
 Set times(SigNum) = nothing
 Set values(SigNum) = nothing
 if err.number<>0 or SigCount<SigNum+1 then
  ReDim Preserve dates(SigNum+1)
     ReDim Preserve times(SigNum+1)
     ReDim Preserve values(SigNum+1)
     ReDim Preserve SigCounts(SigNum+1)
     SigCount = SigNum+1
 end if
 Set dates(SigNum) = CreateObject("Stock.Array")
 Set times(SigNum) = CreateObject("Stock.Array")
 Set values(SigNum) = CreateObject("Stock.Array")
 dates(SigNum).RemoveAll
 times(SigNum).RemoveAll
 values(SigNum).RemoveAll
 SigCounts(SigNum) = Count
End Function

 

第二步:Perl公式代碼修改為以下框架:

///////////////固定的開頭,您僅可以修改“保留信號數”以及“策略號”/////////////////////////////////////////////////

GLOBALVARIABLE:d=0,t=0,next_sig_pos=0,保留信號數=20,策略號=0;
mylot:holding,NODRAW;
if BARPOS=1 then
begin
 if EXTGBDATA(\'股指合約切換\')=1 then
 begin
  d:=0;
  t:=0;
  //EXTGBDATASET(\'股指合約切換\',0);
 end;
 if d=0 and t=0 then
 begin
  xxx:=INIT_SIG(策略號,保留信號數);
 end
 else begin
  xxx:=round(READSIG(策略號));
  if xxx=1 then
  begin
   d:=0;
   t:=0;
   next_sig_pos=0;
   xxx:=INIT_SIG(策略號,保留信號數);
  end
  else
   next_sig_pos:=1;
 end;
end;

if barpos=next_sig_pos then
begin
 myholding:=round(extgbdata(\'HH\' & strright(numtostr(1000+策略號,0),3) & numtostr(barpos,0)))-holding;
 next_sig_pos:=round(extgbdata(\'PP\' & strright(numtostr(1000+策略號,0),3) & numtostr(barpos,0)));
 if myholding>0 then
 begin
  pc:=min(abs(min(holding,0)),myholding);
  kc:=myholding-pc;
  sellshort(pc>0 and holding<0,pc,market);
  buy(kc>0 and holding>=0,kc,market);
 end
 else if myholding<0 then
 begin
  pc:=min(max(holding,0),abs(myholding));
  kc:=abs(myholding)-pc;
  sell(pc>0 and holding>0,pc,market);
  buyshort(kc>0 and holding<=0,kc,market);
 end;
end;

if date()<d or (date()=d and time()<=t) or ISLASTBAR then exit;

//////////////////////////////////////////////////////////////////////////////////////////////////////

 

//這里本應省略N行代碼,這是您原來的策略代碼,為了使您馬上能測試,我隨便寫了個簡單的策略,請不要照用

issell:=close<open and CALLSTOCK(STKLABEL,vtCLOSE,1,-1)<CALLSTOCK(STKLABEL,vtOpen,1,-1);//2連陰空
isbuy:=close>open and CALLSTOCK(STKLABEL,vtCLOSE,1,-1)>CALLSTOCK(STKLABEL,vtOpen,1,-1);//2連陽多

sell(holding>0 and issell,1,market);
SELLSHORT(holding<0 and isbuy,1,market);
buyshort(holding=0 and issell,-1,market);
buy(holding=0 and isbuy,1,market);
j:=0;
for i:=1 to 3000 do              //////////這里加了個循環3000次,目的是故意拖慢效率
 j:=j+1;

 

//您的策略代碼可以非常復雜,唯一需要注意的是請保證后面的結束語句能被執行,即至少產生交易信號時不要使用exit

 

/////////////////固定的結束語句,請原封不動//////////////////////////////////////////////////////////

d:=date();
t:=time();
if (mylot<>holding) then xxx:=round(INSERTSIG(策略號,d,t,holding));

 

一般策略卡的原因:

為了優化代碼執行效率,使得特別復雜的策略運行起來也不會卡,我專門研究了金字塔公式的執行過程,發現“逐K線計算”+“僅刷最后一根K線”模式的運行原理是這樣的:

加載公式到圖表,或公式被初次stkindi:從第1根K線(barpos=1)逐根計算至最后一根K線(barpos=DATACOUNT且islastbar為true

收到新的行情但沒有產生新的K線:僅就最后一根K線進行計算

收到新的行情并且產生新的K線(即新K線收到第一筆行情):從第1根K線(barpos=1)逐根計算至最后一根K線(barpos=DATACOUNT且islastbar為true

由于以上原因,所以勾選“僅刷最后一根K線”后,一般的公式就應該不怎么卡了,但如果你的公式表現還是卡,那就是兩個原因了:

1、盡管每次只計算最后一根K線,但你的代碼對最后K線計算過程非常復雜,導致剛計算完甚至還沒來得及計算完,又收到新的行情了,你的cpu一直處于高度緊張狀態

2、當新K線產生時,雖然你勾選了“僅刷最后一根K線”,但新K線收到第一筆行情時,仍會從barpos=1計算至lastbar,所以你如果用1分鐘周期,那么當計算量非常大時,1分鐘會卡一次

 

我的優化原理:

1、加載公式時,除了你代碼自身優化外,我沒什么能幫你的,所以本策略不能使你的公式加載更快

2、收到新行情但未產生新K線時,我建議你的是采用走完K線模式,所以最后K線完全可以不計算,而只在K線走完時計算倒數第2根K線,所以我遇到islastbar直接exit,這樣在一根K線未走完時,是完全沒有任何計算的

3、只在產生新K線時對倒數第2根K線進行計算,如果該K線產生交易信號,那么調用VBA記錄交易該信號以及產生的K線日期和時間

4、產生新K線時,由于金字塔要求從barpos=1開始重新刷新所有K線,第3點我已經為您記錄了交易信號以及其產生的日期和時間,所以,我會在金字塔重新刷新第一根K線前(barpos=1),再次調用VBA,把所有交易信號(信號產生時間轉換為K線序號)寫入單值全局變量數據庫

5、金字塔重新刷新所有K線時,我幫你直接從單值全局變量數據庫取信號刷新到歷史K線上,而不需要重新計算,直到倒數第2根

 

如果你的代碼不復雜,就不要用這個了,反而弄復雜了,計算量越大才越有效,我示范的代碼加了個循環3000次,可以看出一點都不卡,如果不優化,就很卡了

為了寫得通用,我設了兩個參數,解釋一下

保留信號數=20   //如果設為0表示顯示所有交易信號,如果設20表示僅顯示最后20個信號,設得值越小肯定速度越快,建議設置5~20個左右

策略號=0          //策略號不能重復,如果你有4個策略同時跑,那么請設置不同的策略號,策略號的設置范圍為0~999,如果兩個圖表策略設置相同策略號,將產生沖突

 

最好不要使用ref等金字塔提示不能用在if ... then語句中的函數,如果你要引用前面的周期,建議改為callstock(stklabel,.....)等表達方式,因為金字塔沒有提示在if then中不能用callstock

 

 

假設:你的策略非常復雜,每計算一個K線需要0.2秒,使用一分鐘K線周期,每秒收到兩個tick行情,您的圖表一共有5千根K線,歷史上一共產生了200個交易信號

那么,我可以為您做個優化前后的對比:

 

優化前:每收到一個tick行情需要計算0.1秒,每秒需要計算兩次,即0.2秒;每根K線走完需要進行一次5千根K線的循環計算,即500秒(那肯定是卡死了),您以前唯一可以優化的是點那個“快速”按鈕,假如您輸入的是100根K線,那么您的程序1分鐘也會卡住10秒鐘,如果你的信號跨度比較大,比如有可能持倉超過100根K線,那么此方法還行不通了

 

優化后:一分鐘時間內只需要調用最多兩次VBA,寫和讀200次單值全局變量數據庫,200個交易指令,一次完整的K線運算,具體如下:

收到新行情時,直接退出,不消耗cpu;每走完一根K線時,需要調用一次VBA(消耗0.00001秒),把歷史上的200個交易信號寫入單值全局變量數據庫,需要寫200次全局變量(需要0.000002*200=0.0004秒),以上過程加上數據處理的時間(主要是將信號產生的日期和時間轉換為K線序號),我算他0.1秒是綽綽有余了。另外需要0.1秒計算倒數第二根K線,如果這根K線產生了信號,那么需要再次調用VBA把信號記錄(這個記錄操作我也算他0.1秒)。再加上金字塔本身循環5000個K線所需的時間(但沒有任何代碼去處理他),這個沒測過,應該很快( m.kzuj.com.cn )

也就是,最多消耗0.3秒左右即可完成,比之前的大大提高了。

注:關于調用VBA和單值全局變量數據庫的操作速度,可參考我另外一個帖子的測試結果,結果顯示 GLOBALVARIABLE快于 單值全局變量數據庫 快于VBA調用,所以我寫程序的時候盡可能把VBA調用次數減少到最低,并且能用GLOBALVARIABLE就不用EXTGBxxx

 

{別忘了將本網告訴您身邊的朋友,向朋友傳達有用資料,也是一種人情,你朋友會感謝你的。}

 

 

有思路,想編寫各種指標公式,程序化交易模型,選股公式,預警公式的朋友

可聯系技術人員 QQ: 1145508240  有需要幫忙請點擊這里留言!!!進行 有償 編寫!不貴!點擊查看價格!

 


【字體: 】【打印文章】【查看評論

相關文章

    沒有相關內容
  主站蜘蛛池模板: 成 人 色综合 | 一级特黄aaa大片免费看 | 亚洲天堂视频在线播放 | 人人爽人人澡人人高潮 | 欧美一级视频在线观看欧美 | 亚洲va欧美va国产va天堂影 | 又黄又爽又色的视频 | 天天操天天操天天操香蕉 | 成人嘿嘿视频网站在线 | 国产日韩亚洲欧美 | 天天射综合| aaaa毛片| 人人爱天天做夜夜爽 | 成a人v欧美综合天堂 | 亚洲欧美精品久久 | 国产a级特黄的片子视频 | 很黄很色很爽无病毒网站 | 亚洲黄色在线视频 | 久草免费手机视频 | 午夜伦理片在线观看 | 久久五月天综合 | 欧美成人se01短视频在线看 | 性欧美极品另类 | 国产在线高清视频 | 国内精品小视频在线 | 涩涩网页 | 久爱午夜精品免费视频 | 日韩福利影视 | 欧美天天视频 | 国产亚洲精品国产第一 | 亚洲无线视频 | 久久精品天天中文字幕人 | 日韩综合一区 | 国产一二三四区中 | 波多野野结衣1区二区 | 欧美在线一二三区 | 欧美人成网站免费大全 | xxxx国产 | 123456成年免费视频 | 国产一级淫片免费播放 | 操的网站|