股票量化軟件:衡量指標信息
概述
機器學習依靠數(shù)據訓練來學習市場的一般行為,最終做出相當準確的預測。 所選學習算法必須遍歷精心挑選的樣本,以便提取有意義的信息。 許多人未能成功應用這些精密工具的原因是,大多數(shù)有意義的信息都隱藏在嘈雜的數(shù)據當中。 對于許多策略開發(fā)人員來說可能并不清楚,他們選取的數(shù)據集可能不適合模型訓練。
指標可考慮作為針對基礎價格序列攜帶有關信息的提供者。 利用這個前提,熵可以用來衡量指標傳達了多少信息。 使用 Timothy Masters 撰寫的《測試和優(yōu)調市場交易系統(tǒng)(TTMTS)》一書中記錄的步驟和工具,赫茲股票量化軟件來演示如何使用這些步驟和工具來評估指標數(shù)據的結構。

來百度APP暢享高清圖片
為什么要衡量指標信息
通常,在使用機器學習工具進行策略開發(fā)時,赫茲股票量化軟件只是簡單地將各種數(shù)據扔給算法,希望能從中得到一些結果。 最終的成功將取決于模型中所用的預測變量的品質,且有效的預測因子通常具有某種特征。 其中之一充滿了重要的信息內容。
在模型訓練的變量中信息量很重要,但并不是有效模型訓練的唯一要求。 因此,衡量信息內容可在訓練過程中篩選盲目選用的指標。
熵
在?MQL5.com?上撰寫有關熵的文章已有很多次了。 赫茲股票量化軟件要向讀者們道歉,因為他們將不得不忍受另一個定義,但赫茲股票量化軟件保證這對于理解該概念的應用至關重要。 之前的文章已經提供了熵計算的歷史和推導,所以為了簡潔起見,赫茲股票量化軟件直接從方程開始。

H(X) 表示 X 的熵,X 是表示任意變量的離散變量,例如一條消息。 消息的內容只能假定有限數(shù)量的值。 這在等式中表示為小寫的 x。 小寫 x 是消息的觀測值,如此,如果 x 的所有可能值都可在一個集合 N 中列舉。
研究一個公平骰子的例子。 擲骰子時,可以被視為提供信息,判定游戲的結果。 骰子有 6 條獨特的邊,編號為 1 到 6。 觀察到任何朝上的數(shù)字的概率是 1/6。
依此示例,大寫 X 是骰子,小寫 x 可以是骰子側面繪制的任何數(shù)字。 所有這些都置于集合 N ={ 1,2,3,4,5,6}。 應用公式,這個骰子的熵是 0.7781。

現(xiàn)在考慮另一個骰子,它有制造缺陷。 它有 2 個面,上面畫著相同的數(shù)字。 對于這個有缺陷的骰子,集合 N 的可能值是 {1,1,3,4,5,6}。 再次使用該公式,赫茲股票量化軟件得到的平均熵值為 0.6778。

比較這些值,赫茲股票量化軟件注意到信息內容減少了。 分析兩個骰子,當觀察每個可能值的概率都相等時,熵方程產生其最大可能值。 因此,當所有可能值的概率相等時,熵達到其最大平均值。
如果赫茲股票量化軟件丟棄有缺陷的骰子,作為產生傳統(tǒng)實數(shù)輸出的指標。 那么,X 成為指標,小寫 x 則將是指標可以承擔的數(shù)值范圍。 在繼續(xù)之前,赫茲股票量化軟件遇到了一個問題,因為熵方程嚴格處理離散變量。 變換方程操控連續(xù)變量是可能的,但是這樣應用是困難的,故此堅持離散數(shù)的領域更容易。
計算指標的熵
若要將熵方程應用于連續(xù)變量,赫茲股票量化軟件必須指標的值離散化。這是通過將數(shù)值范圍劃分為大小相等的區(qū)間,然后計算落入每個區(qū)間的數(shù)值個數(shù)來完成的。 使用這種方法,枚舉指標所有值的最大范圍的原始集合被被子集替換,每個子集都是選定的區(qū)間。
在處理連續(xù)變量時,可以依據變量假設概率變化的可能值,因為它顯然為熵應用于指標提供了一個重要的方面。
回到拋骰子的第一個例子。 如果赫茲股票量化軟件將最終熵值的每一個除以各自熵 n 的 log(N)。 第一個骰子產生 1,而有缺陷的骰子產生 0.87。 將熵值除以變量數(shù)值個數(shù)的對數(shù),可以假設產生的度量對應于變量的理論最大熵。 其可稱為比例或相對熵。
正是這個數(shù)值,在赫茲股票量化軟件評估指標時起到大用,因為該指標能示意熵與其理論最大平均值的接近程度。 它越接近最大值那一側越好,而指標另一個端點的任何內容也許是暗示,在任何類型的機器學習嘗試中,該指標都只是一個劣等候選者。

最終應用的等式如上所示,代碼在下面以 mql5 腳本實現(xiàn),可在文章末尾的附件里下載。 使用該腳本,赫茲股票量化軟件就能夠分析大多數(shù)指標。
計算指標熵的腳本
用戶調用腳本時可調整以下參數(shù):
TimeFrame - 選定分析指標值的時間幀。
IndicatorType - 用戶可在此選擇一個內置指標進行分析。 若要指定自定義指標,請選擇自定義指標選項,并在下一個參數(shù)值中輸入指標名稱。
CustomIndicatorName - 如果上一個參數(shù)選擇了自定義指標選項,則用戶必須在此處輸入正確的指標名稱。
UseDefaults - 如果設置為 true,將使用指標中的硬編碼作為默認的用戶輸入。
IndicatorParameterTypes - 這是以逗號分隔的字符串,必須按照正確順序列出指標的數(shù)據類型 — 一個可能的輸入示例,假設要分析的指標分別接受 4 個輸入:雙精度、整數(shù)、整數(shù)、字符串類型;用戶只需輸入 “double, integer, integer, string”,也支持縮寫形式 “d, i, i, s”,其中 d= double,i=integer 以及 s=string。 列舉值映射為整數(shù)類型。
IndicatorParameterValues - 與前面的輸入一樣,這也是一個以逗號分隔的數(shù)值列表,例如,使用前面的示例 “0.5, 4, 5, string_value”。 如果指標參數(shù)值或指標參數(shù)類型的參數(shù)格式有任何錯誤,將導致指標的默認值無法破譯,或丟失。
檢查智能系統(tǒng),以便獲取錯誤消息。 請注意,此處無需包含指標名稱,如果考慮自定義指標,則必須由 CustomIndicatorName 指定。IndicatorBuffer - 用戶可以規(guī)定要分析的指標緩沖區(qū)編號。
HistoryStart - 歷史記錄樣本的開始日期。
HistorySize - 相對于歷史開始要分析的柱線數(shù)量。
Intervals - 此參數(shù)指示為離散化過程創(chuàng)建的編號間隔。 TTMTS 的作者為幾千個樣本量指定了 20 個區(qū)間,其中 2 個被規(guī)定為硬性最小值。赫茲股票量化軟件已在相應的數(shù)值上添加了自己的數(shù)值轉輪,則相對于樣本大小實現(xiàn)了改變區(qū)間數(shù)的可能性,特別是每 1000 個樣本可劃分 51 個。 如果用戶輸入的任何值小于 2,則此選項可用。 故此,需要明確的是,將區(qū)間設置為任何小于 2 的數(shù)字,使用的區(qū)間數(shù)量將根據所分析的柱線數(shù)量而變化。
//--- input parametersinput ENUM_TIMEFRAMES Timeframe=0;input ENUM_INDICATOR ?IndicatorType=IND_BEARS;input string ? CustomIndicatorName="";input bool ? ? UseDefaults=true;input string ? IndicatorParameterTypes="";input string ? IndicatorParameterValues="";input int ? ? ?IndicatorBuffer=0;input datetime HistoryStart=D'2023.02.01 04:00';input int HistorySize=50000;input int ? ? ?Intervals=0;int handle=INVALID_HANDLE;double buffer[];MqlParam b_params[];//+------------------------------------------------------------------+//| Script program start function ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?|//+------------------------------------------------------------------+void OnStart() ?{ ? if(!processParameters(UseDefaults,b_params)) ? ? ?return; ? int y=10; ? while(handle==INVALID_HANDLE && y>=0) ? ? { ? ? ?y--; ? ? ?handle=IndicatorCreate(Symbol(),Timeframe,IndicatorType,ArraySize(b_params),b_params); ? ? }//--- ? if(handle==INVALID_HANDLE) ? ? { ? ? ?Print("Invalid indicator handle, error code: ",GetLastError()); ? ? ?return; ? ? } ? ResetLastError();//--- ? if(CopyBuffer(handle,IndicatorBuffer,HistoryStart,HistorySize,buffer)<0) ? ? { ? ? ?Print("error copying to buffer, returned error is ",GetLastError()); ? ? ?IndicatorRelease(handle); ? ? ?return; ? ? }//--- ? Print("Entropy of ",(IndicatorType==IND_CUSTOM)?CustomIndicatorName:EnumToString(IndicatorType)," is ",relativeEntroy(Intervals,buffer));//--- ? IndicatorRelease(handle); ?}//+------------------------------------------------------------------+//+------------------------------------------------------------------+//| ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?|//+------------------------------------------------------------------+bool processParameters(bool use_defaults,MqlParam ¶ms[]) ?{ ? bool custom=(IndicatorType==IND_CUSTOM); ? string ind_v[],ind_t[]; ? int types,values; ? if(use_defaults) ? ? ?types=values=0; ? else ? ? { ? ? ?types=StringSplit(IndicatorParameterTypes,StringGetCharacter(",",0),ind_t); ? ? ?values=StringSplit(IndicatorParameterValues,StringGetCharacter(",",0),ind_v); ? ? } ? int p_size=MathMin(types,values); ? int values_to_input=ArrayResize(params,(custom)?p_size+1:p_size); ? if(custom) ? ? { ? ? ?params[0].type=TYPE_STRING; ? ? ?params[0].string_value=CustomIndicatorName; ? ? }//if(!p_size)// ?return true; ? if(use_defaults) ? ? ?return true; ? int i,z; ? int max=(custom)?values_to_input-1:values_to_input; ? for(i=0,z=(custom)?i+1:i; i<max; i++,z++) ? ? { ? ? ?if(ind_t[i]=="" || ind_v[i]=="") ? ? ? ?{ ? ? ? ? Print("Warning: Encountered empty string value, avoid adding comma at end of string parameters"); ? ? ? ? break; ? ? ? ?} ? ? ?params[z].type=EnumType(ind_t[i]); ? ? ?switch(params[z].type) ? ? ? ?{ ? ? ? ? case TYPE_INT: ? ? ? ? ? ?params[z].integer_value=StringToInteger(ind_v[i]); ? ? ? ? ? ?break; ? ? ? ? case TYPE_DOUBLE: ? ? ? ? ? ?params[z].double_value=StringToDouble(ind_v[i]); ? ? ? ? ? ?break; ? ? ? ? case TYPE_STRING: ? ? ? ? ? ?params[z].string_value=ind_v[i]; ? ? ? ? ? ?break; ? ? ? ? default: ? ? ? ? ? ?Print("Error: Unknown specified parameter type"); ? ? ? ? ? ?break; ? ? ? ?} ? ? } ? return true; ?}//+------------------------------------------------------------------+//| ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?|//+------------------------------------------------------------------+ENUM_DATATYPE EnumType(string type) ?{ ? StringToLower(type); ? const ushort firstletter=StringGetCharacter(type,0); ? switch(firstletter) ? ? { ? ? ?case 105: ? ? ? ? return TYPE_INT; ? ? ?case 100: ? ? ? ? return TYPE_DOUBLE; ? ? ?case 115: ? ? ? ? return TYPE_STRING; ? ? ?default: ? ? ? ? Print("Error: could not parse string to match data type"); ? ? ? ? return ENUM_DATATYPE(-1); ? ? } ? return ENUM_DATATYPE(-1); ?}//+------------------------------------------------------------------+
只需注意為間隔選擇的值:更改計算中使用的間隔數(shù),將改變最終熵值。 在進行分析時,明智的做法是保持某種一致性,以盡量減少所使用的獨立輸入的影響。 在腳本中,相對熵計算封裝在 Entropy.mqh 文件中定義的函數(shù)之中。
該腳本只是在智能系統(tǒng)選項卡中打印生成的熵值。 很對各種內置和自定義指標運行腳本,會產生如下所示的結果。 有趣的是,威廉的百分比范圍具有接近完美的相對熵。 將其與市場促進指數(shù)指標進行比較,后者顯示令人失望的結果。

有了這些結果,赫茲股票量化軟件就可以采取進一步的步驟來處理數(shù)據,令其適合機器學習算法。 這涉及對指標的統(tǒng)計屬性進行嚴格分析。 研究指標值的分布將揭示歪斜和異常值的任何問題。 所有這些都會降低模型訓練。
作為一個示例,赫茲股票量化軟件檢查上面分析的兩個指標的一些統(tǒng)計屬性。

威廉姆斯百分比范圍的分布幾乎揭示了所有數(shù)值如何分布在整個范圍內,除了多模態(tài)之外,分布相當均勻。 這樣的分布是理想的,反映在熵值中。
這與市場促進指數(shù)的長尾分布形成鮮明對比。 這樣的指標對于大多數(shù)學習算法來說都是有問題的,需要轉換值。 轉換這些值應該會導致指標相對熵的改善。
改進指標的信息內容
應該指出的是,提升指標熵的變化不應被視為提高指標提供的信號準確性的一種方式。 提高熵不會把一個無用的指標變成圣杯。 提高熵是關于處理指標數(shù)據,以便在預測模型中有效使用。
當熵值糟糕到無可救藥,任何遠低于 0.5,且接近零的值時,應考慮此選項。 上限閾值純粹是任意的。 其為開發(fā)人員選擇的最小可接受值。 重點是產生盡可能接近均勻的指標值分布。 應用轉換的決定應基于對大量具有代表性的指標值樣本進行的分析。
所應用的轉換不應改變指標的基礎行為。 轉換后的指標應具有與原始指標相似的形狀,例如波谷和峰值的位置在兩個序列中應相似。 如果不是這種情況,那么赫茲股票量化軟件就有可能丟失潛在的有用信息。
針對測試數(shù)據缺陷的不同方面有許多轉換方法。 赫茲股票量化軟件將只研究一些簡單的轉換,這些轉換旨在修復通過基本統(tǒng)計分析發(fā)現(xiàn)的明顯缺陷。 預處理是機器學習的一個廣闊分支。 任何希望掌握機器學習方法應用的人,建議在該領域獲取更多知識。
為了描述某些轉換的效果,赫茲股票量化軟件提供了一個腳本,該腳本可以選擇應用各種轉換,并顯示正在分析的數(shù)據的分布。 該腳本實現(xiàn)了 6 個轉換函數(shù)的示例:
平方根函數(shù)變換適用于壓制偶爾偏離大多數(shù)指標值的指標值。
立方根變換是另一個壓制函數(shù),最好應用于負值指標。
而對數(shù)變換壓縮數(shù)值的程度比前面提到的壓縮變換更大。
雙曲正切變換和邏輯變換應用于合適尺度的數(shù)據值,以避免產生無效數(shù)字(NAN 錯誤)的問題。
極值變換在數(shù)據集中引起極端均勻性。 它只應適用于產生大部分獨特值,但很少有相似數(shù)字的指標。
用于比較變換后的指標值的腳本
與早期的腳本相比,它包含了相同的用戶輸入來指定要分析的指標。 新輸入說明如下:
DisplayTime - 腳本顯示指標分布的圖形。 DisplayTime 是以秒為單位的整數(shù)值,這是圖形在被刪除之前可見的時間量。
ApplyTransfrom - 是設置腳本模式的布爾值。 當為 false 時,腳本繪制分布,并顯示樣本的基本統(tǒng)計數(shù)據,以及相對熵。 如果設置為 true,則對原始指標值應用變換,并顯示變換前后的相對熵值。 修改后的樣本分布繪制為紅色曲線。
Select_transform - 是一個枚舉,提供前面描述的可應用變換,有可能提高指標熵。
//+------------------------------------------------------------------+//| ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?IndicatorAnalysis.mq5 |//| ? ? ? ? ? ? ? ? ? ? ? ?Copyright 2023, MetaQuotes Software Corp. |//| ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? https://www.mql5.com |//+------------------------------------------------------------------+#property copyright "Copyright 2023, MetaQuotes Software Corp."#property link ? ? ?"https://www.mql5.com"#property version ? "1.00"#property script_show_inputs#include<Entropy.mqh>//--- input parametersinput ENUM_TIMEFRAMES Timeframe=0;input ENUM_INDICATOR ?IndicatorType=IND_CUSTOM;input string ? CustomIndicatorName="";input bool ? ? UseDefaults=false;input string ? IndicatorParameterTypes="";input string ? IndicatorParameterValues="";input int ? ? ?IndicatorBuffer=0;input datetime HistoryStart=D'2023.02.01 04:00';;input int HistorySize=50000;input int DisplayTime=30;//secs to keep graphic visibleinput bool ApplyTransform=true;input ENUM_TRANSFORM Select_transform=TRANSFORM_LOG;//Select function transformint handle=INVALID_HANDLE;double buffer[];MqlParam b_params[];//+------------------------------------------------------------------+//| Script program start function ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?|//+------------------------------------------------------------------+void OnStart() ?{//--- ? if(!processParameters(UseDefaults,b_params)) ? ? ?return; ? int y=10; ? while(handle==INVALID_HANDLE && y>=0) ? ? { ? ? ?y--; ? ? ?handle=IndicatorCreate(_Symbol,Timeframe,IndicatorType,ArraySize(b_params),b_params); ? ? }//--- ? if(handle==INVALID_HANDLE) ? ? { ? ? ?Print("Invalid indicator handle, error code: ",GetLastError()); ? ? ?return; ? ? } ? ResetLastError();//--- ? if(CopyBuffer(handle,IndicatorBuffer,HistoryStart,HistorySize,buffer)<0) ? ? { ? ? ?Print("error copying to buffer, returned error is ",GetLastError()); ? ? ?IndicatorRelease(handle); ? ? ?return; ? ? }//--- ? DrawIndicatorDistribution(DisplayTime,ApplyTransform,Select_transform,IndicatorType==IND_CUSTOM?CustomIndicatorName:EnumToString(IndicatorType),buffer);//--- ? IndicatorRelease(handle); ?}//+------------------------------------------------------------------+bool processParameters(bool use_defaults,MqlParam ¶ms[]) ?{ ? bool custom=(IndicatorType==IND_CUSTOM); ? string ind_v[],ind_t[]; ? int types,values; ? if(use_defaults) ? ? ?types=values=0; ? else ? ? { ? ? ?types=StringSplit(IndicatorParameterTypes,StringGetCharacter(",",0),ind_t); ? ? ?values=StringSplit(IndicatorParameterValues,StringGetCharacter(",",0),ind_v); ? ? } ? int p_size=MathMin(types,values); ? int values_to_input=ArrayResize(params,(custom)?p_size+1:p_size); ? if(custom) ? ? { ? ? ?params[0].type=TYPE_STRING; ? ? ?params[0].string_value=CustomIndicatorName; ? ? } ? if(use_defaults) ? ? ?return true; ? int i,z; ? int max=(custom)?values_to_input-1:values_to_input; ? for(i=0,z=(custom)?i+1:i; i<max; i++,z++) ? ? { ? ? ?if(ind_t[i]=="" || ind_v[i]=="") ? ? ? ?{ ? ? ? ? Print("Warning: Encountered empty string value, avoid adding comma at end of string parameters"); ? ? ? ? break; ? ? ? ?} ? ? ?params[z].type=EnumType(ind_t[i]); ? ? ?switch(params[z].type) ? ? ? ?{ ? ? ? ? case TYPE_INT: ? ? ? ? ? ?params[z].integer_value=StringToInteger(ind_v[i]); ? ? ? ? ? ?break; ? ? ? ? case TYPE_DOUBLE: ? ? ? ? ? ?params[z].double_value=StringToDouble(ind_v[i]); ? ? ? ? ? ?break; ? ? ? ? case TYPE_STRING: ? ? ? ? ? ?params[z].string_value=ind_v[i]; ? ? ? ? ? ?break; ? ? ? ? default: ? ? ? ? ? ?Print("Error: Unknown specified parameter type"); ? ? ? ? ? ?break; ? ? ? ?} ? ? } ? return true; ?}//+------------------------------------------------------------------+//| ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?|//+------------------------------------------------------------------+ENUM_DATATYPE EnumType(string type) ?{ ? StringToLower(type); ? const ushort firstletter=StringGetCharacter(type,0); ? switch(firstletter) ? ? { ? ? ?case 105: ? ? ? ? return TYPE_INT; ? ? ?case 100: ? ? ? ? return TYPE_DOUBLE; ? ? ?case 115: ? ? ? ? return TYPE_STRING; ? ? ?default: ? ? ? ? Print("Error: could not parse string to match data type"); ? ? ? ? return ENUM_DATATYPE(-1); ? ? } ? return ENUM_DATATYPE(-1); ?}//+------------------------------------------------------------------+
繼續(xù)分析示例,赫茲股票量化軟件比較平方根和立方根變換的應用。


兩者都提供了熵的改進,但右尾可能有問題,到目前為止應用的兩種變換都無法有效地處理它。

對數(shù)變換會產生更好的熵值。 尾巴仍然相當明顯。 作為最后的手段,赫茲股票量化軟件可以應用極值變換。
結束語
赫茲股票量化軟件探索了熵的概念,以便估算預測模型訓練之前需要轉換指標值。
該概念在兩個腳本中實現(xiàn)。 即 EntropyIndicatorAnalyis,它在智能系統(tǒng)選項卡中打印樣本的相對熵。 另一個腳本 IndicatorAnalysis 更進一步,繪制原始和變換指標值的分布,同時顯示前后相對熵值。
雖然這些工具可能很實用,但應該注意的是,它們不能應用于所有類型的指標。 通常,包含空值的基于箭頭的指標不適合此處描述的腳本。 在這種情況下,運用其他編碼技術將是必要的。
數(shù)據變換主題只是構建任何類型的預測模型時應考慮的可能預處理步驟的子集。 運用這些技術將有助于提取真正獨特的關系,從而提供擊敗市場所需的優(yōu)勢。

舉報/反饋