專門設(shè)計(jì)的方法還可以針對選定的金融產(chǎn)品或一組產(chǎn)品逐一分析每種形態(tài)。 它還允許在預(yù)定義參數(shù)(包括時間幀或樣本范圍)之間找到可能的相關(guān)性,以及特別的衡量數(shù)據(jù),例如出現(xiàn)頻率,在形態(tài)形成后特定方向上的走勢概率。
分析方法僅涉及從大量現(xiàn)有燭條樣式中選擇出的 14 種形態(tài)。 由于不可能逐一分析所有形態(tài),所以找到了另一種解決方案。 之前驗(yàn)證所有形態(tài)的關(guān)鍵特征是依據(jù)它們的基礎(chǔ),即它們的組成部分。 已分析燭條形態(tài)當(dāng)中,有四種由一根燭條組成,其余十種由兩根燭條組成。 已分析燭條形態(tài)由六種燭條類型的不同集合或序列所組成。
形態(tài)的主要問題是它們很久之前出現(xiàn),而市場屬性、行為和動態(tài)則是持續(xù)變化。 為了與市場分析趨勢保持一致,應(yīng)在形態(tài)分析中進(jìn)行一些變通。 在本文中,我們研究一套基于已知燭條類型搜索并測試新燭條形態(tài)的系統(tǒng)。
因此,我們有了一個燭條形態(tài)池,新的形態(tài)將在其中形成。 這些新形態(tài)將包含 1-3 根燭條,有或沒有反復(fù)。 這個形態(tài)池將完全包含 11 種基本燭條。 生成的燭條形態(tài)將根據(jù)相同的原理進(jìn)行分析,這在 第一篇文章 中已有闡述。
第三個選項(xiàng)卡 設(shè)置 已被大幅修改。 在此選項(xiàng)卡中正確配置參數(shù)是必不可少的,這就是為什么我們將會更詳盡地研究它。

圖例 3 更新的 “設(shè)置” 選項(xiàng)卡。
- 添加了簡單燭條類型,及其名稱的編號。 因此,我們可以輕松地將視覺表現(xiàn)與 “所用蠟燭” 列表相對應(yīng)。
- 添加了選擇界面語言的選項(xiàng)。 俄語或英語。
- '所用蠟燭' 列表,即形態(tài)的參與者。 復(fù)選框允許選擇所需的測試類型。
- 一組可切換按鈕。 只能選擇一個位置。 這樣我們就可以避免在 AutoSearch 選項(xiàng)卡中重載生成的形態(tài)列表。
- 兩個可切換按鈕。 '反復(fù)'(疊加)意味著形態(tài)中只能有一個燭條類型。 示例是由三根空頭 Marubozu 燭條組成的形態(tài)。 與此同時,尖頂 - Marubozu - Marubozu 形態(tài)也可以存在。
工具實(shí)現(xiàn)
我們已判定在現(xiàn)有應(yīng)用程序中需要實(shí)現(xiàn)的關(guān)鍵附加項(xiàng)。 現(xiàn)在我們來繼續(xù)實(shí)現(xiàn)它。 首先,我們需要添加一個額外的選項(xiàng)卡。 選項(xiàng)卡的索引將會變化。 AutoSearch 選項(xiàng)卡的索引為 1,此編號之前用于 設(shè)置 選項(xiàng)卡。 現(xiàn)在 “設(shè)置” 使用編號 2。 當(dāng)鏈接子元素時必須要考慮這一點(diǎn)。 所以,我們需要將 “設(shè)置” 選項(xiàng)卡所有子元素的索引從 1 更改為 2。
// ------------------------------------------------------------------
//| 創(chuàng)建一個選項(xiàng)卡組 |
// ------------------------------------------------------------------
bool CProgram::CreateTabs(const int x_gap,const int y_gap)
{
#define TABS1_TOTAL 3
//--- 將指針存儲到主控件
m_tabs1.MainPointer(m_window1);
//--- 屬性
m_tabs1.IsCenterText(true);
m_tabs1.PositionMode(TABS_TOP);
m_tabs1.AutoXResizeMode(true);
m_tabs1.AutoYResizeMode(true);
m_tabs1.AutoXResizeRightOffset(3);
m_tabs1.AutoYResizeBottomOffset(25);
//--- 添加指定屬性的選項(xiàng)卡
string tabs_names[TABS1_TOTAL]={'Analysis','Auto search','Settings'};
for(int i=0; i<TABS1_TOTAL; i )
m_tabs1.AddTab(tabs_names[i],150);
//--- 創(chuàng)建控件
if(!m_tabs1.CreateTabs(x_gap,y_gap))
return(false);
//--- 將對象添加到公共對象組數(shù)組中
CWndContainer::AddToElementsArray(0,m_tabs1);
return(true);
}
AutoSearch 選項(xiàng)卡的子元素與 分析 選項(xiàng)卡的子元素類似。 僅有的區(qū)別是第一列的名稱和配色方案。 這允許在視覺上區(qū)分這些標(biāo)簽的界面元素。
// ------------------------------------------------------------------
//| 為控件創(chuàng)建窗體 |
// ------------------------------------------------------------------
bool CProgram::CreateWindow(const string caption_text)
{
//--- 將指針添加到窗口數(shù)組
CWndContainer::AddWindow(m_window1);
//--- 屬性
m_window1.XSize(750);
m_window1.YSize(500);
m_window1.FontSize(9);
m_window1.IsMovable(true);
m_window1.CloseButtonIsUsed(true);
m_window1.CollapseButtonIsUsed(true);
m_window1.FullscreenButtonIsUsed(true);
m_window1.TooltipsButtonIsUsed(true);
//--- 創(chuàng)建窗體
if(!m_window1.CreateWindow(m_chart_id,m_subwin,caption_text,5,5))
return(false);
//--- 選卡
if(!CreateTabs(3,43))
return(false);
//--- “分析” 選卡
//--- 可編輯字段
if(!CreateSymbolsFilter(m_symb_filter1,10,10,'Symbols',0))
return(false);
if(!CreateRequest(m_request1,250,10,'Search',0))
return(false);
if(!CreateRange(m_range1,485,10,'Range',0))
return(false);
//--- 組合框
if(!CreateComboBoxTF(m_timeframes1,350,10,'Timeframe',0))
return(false);
//--- 創(chuàng)建品種表格
if(!CreateSymbTable(m_symb_table1,10,50,0))
return(false);
//--- 創(chuàng)建結(jié)果表格
if(!CreateTable1(m_table1,120,50,0))
return(false);
//--- “AutoSearch” 選卡
//--- 可編輯字段
if(!CreateSymbolsFilter(m_symb_filter2,10,10,'Symbols',1))
return(false);
if(!CreateRequest(m_request2,250,10,'Search',1))
return(false);
if(!CreateRange(m_range2,485,10,'Range',1))
return(false);
//--- 組合框
if(!CreateComboBoxTF(m_timeframes2,350,10,'Timeframe',1))
return(false);
//--- 創(chuàng)建品種表格
if(!CreateSymbTable(m_symb_table2,10,50,1))
return(false);
//--- 創(chuàng)建結(jié)果表格
if(!CreateTable2(m_table2,120,50,1))
return(false);
從上面的代碼中您可以看出,區(qū)別只涉及兩個方法 CreateTable1() 和 CreateTable2()。 現(xiàn)在,我們進(jìn)入 “設(shè)置” 選項(xiàng)卡。 這里的第一個變化涉及圖形資源。 燭條參數(shù)設(shè)置元素也已添加到創(chuàng)建元素中。 這是由 CreateNameCandle() 方法完成的。
// ------------------------------------------------------------------
//| 創(chuàng)建燭條設(shè)置元素 |
// ------------------------------------------------------------------
#resource '\\Images\\EasyAndFastGUI\\Icons\\bmp16\\settings_dark.bmp'
#resource '\\Images\\EasyAndFastGUI\\Candles\\long.bmp'
#resource '\\Images\\EasyAndFastGUI\\Candles\\short.bmp'
#resource '\\Images\\EasyAndFastGUI\\Candles\\doji.bmp'
#resource '\\Images\\EasyAndFastGUI\\Candles\\spin.bmp'
#resource '\\Images\\EasyAndFastGUI\\Candles\\maribozu.bmp'
#resource '\\Images\\EasyAndFastGUI\\Candles\\hammer.bmp'
//---
bool CProgram::CreateCandle(CPicture &pic,CButton &button,CTextLabel &candlelabel,const string candlename,const int x_gap,const int y_gap,string path)
{
//--- 將指針存儲到主控件
pic.MainPointer(m_tabs1);
//--- 附加到選卡
m_tabs1.AddToElementsArray(2,pic);
//--- 屬性
pic.XSize(64);
pic.YSize(64);
pic.IconFile(path);
//--- 創(chuàng)建按鈕
if(!pic.CreatePicture(x_gap,y_gap))
return(false);
//--- 將指向元素的指針添加到基類
CWndContainer::AddToElementsArray(0,pic);
CreateButtonPic(pic,button,'Images\\EasyAndFastGUI\\Icons\\bmp16\\settings_dark.bmp');
CreateNameCandle(candlelabel,x_gap,y_gap pic.YSize(),candlename);
return(true);
}
這就是全部有關(guān)已創(chuàng)建控件的變化。 現(xiàn)在我們繼續(xù)討論新內(nèi)容。 其中之一是界面語言選擇選項(xiàng)。 該應(yīng)用程序支持兩種語言:俄語和英語。 語言選擇如圖例 4 所示。

圖例 4 界面語言選擇。
從代碼中可以看出,當(dāng)選擇組合框中的項(xiàng)目時,語言變更方法會判斷下拉菜單中的哪些項(xiàng)目被選擇,并據(jù)其設(shè)置相應(yīng)的語言索引:
下一部分負(fù)責(zé)選擇簡單的燭條類型,而測試形態(tài)也會從其中產(chǎn)生。 有 11 種類型。 該控件的實(shí)現(xiàn),作為燭條類型的名稱列表,并含復(fù)選框,可由它們反映所選項(xiàng)目。 CreateListView() 方法用來實(shí)現(xiàn)這個邏輯:
// ------------------------------------------------------------------
//| 創(chuàng)建列表 |
// ------------------------------------------------------------------
bool CProgram::CreateListView(const int x_gap,const int y_gap)
{
//--- 列表視圖的大小
#define CANDLE_TOTAL 11
//--- 將指針存儲到主控件
m_listview1.MainPointer(m_tabs1);
//--- 附加到選卡
m_tabs1.AddToElementsArray(2,m_listview1);
//--- 屬性
m_listview1.XSize(175);
m_listview1.YSize(250);
m_listview1.ItemYSize(19);
m_listview1.LabelXGap(25);
m_listview1.LightsHover(true);
m_listview1.CheckBoxMode(true);
m_listview1.ListSize(CANDLE_TOTAL);
m_listview1.AutoYResizeMode(true);
m_listview1.AutoYResizeBottomOffset(10);
m_listview1.FontSize(10);
//--- 用數(shù)據(jù)填充列表視圖
string cand_name[CANDLE_TOTAL]=
{
'Long — bullish',
'Long — bearish',
'Short — bullish',
'Short — bearish',
'Spinning Top — bullish',
'Spinning Top — bearish',
'Doji',
'Marubozu — bullish',
'Marubozu — bearish',
'Hammer — bullish',
'Hammer — bearish'
};
for(int r=0; r<CANDLE_TOTAL; r )
{
m_listview1.SetValue(r,(string)(r 1) '. ' cand_name[r]);
}
//--- 創(chuàng)建列表視圖
if(!m_listview1.CreateListView(x_gap,y_gap))
return(false);
//--- 將指向元素的指針添加到基類
CWndContainer::AddToElementsArray(0,m_listview1);
return(true);
}
接下來的兩個控件與簡單燭條類型列表直接相關(guān)。 第一個是開關(guān),它啟用或禁用反復(fù)。 正如在任務(wù)定義部分中已經(jīng)提及的,反復(fù)僅與由一根燭條類型組成的形態(tài)有關(guān),而與其大小無關(guān)。

圖例 5 選擇所分析的燭條類型和反復(fù)模式。
負(fù)責(zé)創(chuàng)建反復(fù)開關(guān)的方法稱為 CreateDualButton():
// ------------------------------------------------------------------
//| 創(chuàng)建反復(fù)開關(guān) |
// ------------------------------------------------------------------
bool CProgram::CreateDualButton(CButton &lbutton,CButton &rbutton,const int x_gap,const int y_gap,const string ltext,const string rtext)
{
CreateButton(lbutton,x_gap,y_gap,ltext);
CreateButton(rbutton,x_gap 99,y_gap,rtext);
return(true);
}
// ------------------------------------------------------------------
//| |
// ------------------------------------------------------------------
bool CProgram::CreateButton(CButton &button,const int x_gap,const int y_gap,const string text)
{
//--- 將指針保存到主控件
button.MainPointer(m_tabs1);
//--- 附加到選卡
m_tabs1.AddToElementsArray(2,button);
//--- 屬性
button.XSize(100);
button.YSize(30);
button.Font('Trebuchet');
button.FontSize(10);
button.IsCenterText(true);
button.BorderColor(C'0,100,255');
button.BackColor(clrAliceBlue);
button.BackColorLocked(C'50,180,75');
button.BorderColorLocked(C'50,180,75');
button.LabelColorLocked(clrWhite);
//--- 創(chuàng)建控件
if(!button.CreateButton(text,x_gap,y_gap))
return(false);
//--- 將指向元素的指針添加到基類
CWndContainer::AddToElementsArray(0,button);
return(true);
}
在左鍵單擊事件中跟蹤控件操作設(shè)置:
if(id==CHARTEVENT_CUSTOM ON_CLICK_BUTTON)
{
....
//--- 如果按下按鈕
if(lparam==m_button7.Id())
{
m_button7.IsLocked(true);
m_button8.IsLocked(false);
}
else if(lparam==m_button8.Id())
{
m_button7.IsLocked(false);
m_button8.IsLocked(true);
}
已分析應(yīng)用程序的可視部分后,我們現(xiàn)在進(jìn)入計(jì)算部分。 首先,我們需要判定這些動作的最小設(shè)置、操作順序和處理方法:
步驟 1. 設(shè)置輸入數(shù)據(jù)。
在開始運(yùn)行應(yīng)用程序之前,我們需要選擇簡單的燭條類型,從中生成分析形態(tài)。 然后選擇是否啟用反復(fù)模式。 反復(fù)模式意味著在創(chuàng)建任何大小的形態(tài)時僅使用一根燭條的類型。 然后,選擇形態(tài)中的燭條數(shù)量。 這也許包括一根、兩根或三根燭條的形態(tài)。 請注意,若要生成兩根或三根燭條的形態(tài),必須至少選擇兩根簡單燭條。 如果您嘗試生成燭條較少的形態(tài),應(yīng)用程序?qū)⒎祷劐e誤,如圖例 6 所示。

圖例 6 錯誤:兩根燭條形態(tài)卻僅選擇了一根燭條類型。
步驟 2. 處理 “AutoSearch” 選項(xiàng)卡。
設(shè)置正確的輸入?yún)?shù)后,切換到 “AutoSearch” 并選擇一個品種進(jìn)行測試。 我們來詳細(xì)查看此選項(xiàng)卡中表現(xiàn)的產(chǎn)品能力。
- 選擇并搜索正在分析的貨幣品種。 在輸入字段中,您可以鍵入品種的一部分,或指定所需品種并以逗號分隔,然后單擊 “搜索” 按鈕。 您還可以使用預(yù)定義短語 Major,它顯示主要貨幣對。 若要查看市場觀察窗口中的所有可用品種,您應(yīng)取消選中左上角的選擇框。 這會禁用搜索窗口中的過濾。
- 然后從下拉列表中選擇所需的時間幀,并在所選時間幀內(nèi)劃定樣本范圍的燭條數(shù)量。
- 選擇所需的產(chǎn)品或列表后,單擊當(dāng)前的產(chǎn)品或列表開始分析。 之后,應(yīng)用程序?qū)⑸稍诓襟E 1 中配置的形態(tài),執(zhí)行相應(yīng)的計(jì)算,并在表格中顯示數(shù)據(jù)。 在表格中接收數(shù)據(jù)之后,您可以更改時間幀,并重新計(jì)算實(shí)時數(shù)據(jù)。
我們來詳細(xì)查看結(jié)果數(shù)據(jù)表格。 當(dāng)我們進(jìn)一步考察算法時,這有助于理解其計(jì)算和操作原理。

圖例 7 EURUSD 對的數(shù)據(jù)計(jì)算示例。
從圖例 7 中可以看出,正分析貨幣對的所在行已在品種表格中被選擇。 M15 時間幀和 8000 根 15 分鐘燭條的樣品范圍顯示在右側(cè)部分的頂部。 結(jié)果表格有六列。 此處我們只考慮第一列,而其余的列在第一篇文章的 開發(fā)界面原型 部分已有說明。
第一列是 Set。 在下面的行中,數(shù)值按 [1,1,2] 的格式顯示。 方括號中的三個數(shù)字表示使用三根燭條的形態(tài)。 該形態(tài)由簡單的燭條 1 和 2 組成,完全按方括號中指定的順序排列。 用過的燭條編號可以在 設(shè)置 選卡的 用過的蠟燭 部分找到。

圖例 8 形態(tài)生成中用過的燭條編號和列表。
現(xiàn)在我們知道如何配置和啟動應(yīng)用程序,因此我們可以繼續(xù)考察其內(nèi)部操作邏輯。 設(shè)置輸入數(shù)據(jù)后,我們點(diǎn)擊品種表格中的貨幣產(chǎn)品。 單擊表格單元格的響應(yīng)會調(diào)用 ChangeSymbol2() 方法:
//--- 在列表或表格中選擇項(xiàng)目的事件處理
if(id==CHARTEVENT_CUSTOM ON_CLICK_LIST_ITEM)
{
//--- 品種改變
if(ChangeSymbol1(lparam))
Update(true);
if(ChangeSymbol2(lparam))
m_table2.Update(true);
}
在此方法中,除了在狀態(tài)欄中設(shè)置信息值之外,還有更多的兩個方法。
// ------------------------------------------------------------------
//| 品種改變 |
// ------------------------------------------------------------------
bool CProgram::ChangeSymbol2(const long id)
{
//--- 檢查元素 ID
if(id!=m_symb_table2.Id())
return(false);
//--- 如果該行并非高亮顯示,則退出
if(m_symb_table2.SelectedItem()==WRONG_VALUE)
{
//--- 在狀態(tài)欄中顯示完整的品種說明
m_status_bar.SetValue(0,'No symbol selected for analysis');
m_status_bar.GetItemPointer(0).Update(true);
return(false);
}
//--- 獲取品種
string symbol=m_symb_table2.GetValue(0,m_symb_table2.SelectedItem());
//--- 在狀態(tài)欄中顯示完整的品種說明
string val=(m_lang_index==0)?'Выбранный символ: ':'Selected symbol: ';
m_status_bar.SetValue(0,val ::SymbolInfoString(symbol,SYMBOL_DESCRIPTION));
m_status_bar.GetItemPointer(0).Update(true);
if(!BuildingAutoSearchTable())
return(false);
GetPatternType(symbol,m_total_combination);
return(true);
}
第一個方法是 BuildingAutoSearchTable()。 它按照 設(shè)置 選項(xiàng)卡中簡單燭條列表選擇的項(xiàng)目創(chuàng)建形態(tài),在 用過的蠟燭(圖例 8)中,將其顯示在結(jié)果表格的第一列。
// ------------------------------------------------------------------
//| 重建形態(tài)自動搜索表格 |
// ------------------------------------------------------------------
bool CProgram::BuildingAutoSearchTable(void)
{
//---
if(!GetCandleCombitaion())
{
if(m_lang_index==0)
MessageBox('Число выбранных свечей меньше размера исследуемого паттерна!','Ошибка');
else if(m_lang_index==1)
MessageBox('The number of selected candles is less than the size of the studied pattern!','Error');
return(false);
}
//--- 刪除所有行
m_table2.DeleteAllRows();
//--- 按品種數(shù)量設(shè)置行數(shù)
for(int i=0; i<ArraySize(m_total_combination); i )
{
m_table2.AddRow(i);
m_table2.SetValue(0,i,m_total_combination[i]);
}
m_table2.DeleteRow(ArraySize(m_total_combination));
//--- 更新表格
m_table2.Update(true);
m_table2.GetScrollVPointer().Update(true);
m_table2.GetScrollHPointer().Update(true);
return(true);
}
// ------------------------------------------------------------------
//| 基于簡單燭條生成形態(tài) |
// ------------------------------------------------------------------
bool CProgram::GetCandleCombitaion(void)
{
string candlenumber[];
int selected_candles=0,n;
ArrayResize(candlenumber,m_total_candles);
//---
for(int i=0;i<m_total_candles;i )
{
if(m_listview1.GetState(i))
{
candlenumber[selected_candles]=(string)(i 1);
selected_candles ;
}
}
if((m_pattern_size==2 && selected_candles<2) || (m_pattern_size==3 && selected_candles<2) || selected_candles<1)
return(false);
//--- 計(jì)算組合數(shù)
if(m_pattern_size>1)
n=(m_button7.IsLocked())?(int)MathPow(selected_candles,m_pattern_size):(int)MathPow(selected_candles,m_pattern_size)-selected_candles;
else
n=selected_candles;
ArrayResize(m_total_combination,n);
n=0;
//--- 單根燭條的一個集合
if(m_pattern_size==1)
{
for(int i=0;i<selected_candles;i )
m_total_combination[i]='[' candlenumber[i] ']';
}
//--- 兩根燭條的一個集合
else if(m_pattern_size==2)
{
//--- 啟用反復(fù)模式
if(m_button7.IsLocked())
{
for(int i=0;i<selected_candles;i )
{
for(int j=0;j<selected_candles;j )
{
m_total_combination[n]='[' candlenumber[i] ',' candlenumber[j] ']';
n ;
}
}
}
//--- 禁用反復(fù)模式
else if(m_button8.IsLocked())
{
for(int i=0;i<selected_candles;i )
{
for(int j=0;j<selected_candles;j )
{
if(j!=i)
{
m_total_combination[n]='[' candlenumber[i] ',' candlenumber[j] ']';
n ;
}
}
}
}
}
//--- 三根燭條的集合
else if(m_pattern_size==3)
{
//--- 啟用反復(fù)模式
if(m_button7.IsLocked())
{
for(int i=0;i<selected_candles;i )
{
for(int j=0;j<selected_candles;j )
{
for(int k=0;k<selected_candles;k )
{
m_total_combination[n]='[' candlenumber[i] ',' candlenumber[j] ',' candlenumber[k] ']';
n ;
}
}
}
}
//--- 禁用反復(fù)模式
else if(m_button8.IsLocked())
{
for(int i=0;i<selected_candles;i )
{
for(int j=0;j<selected_candles;j )
for(int k=0;k<selected_candles;k )
{
if(i==j && i==k)
continue;
m_total_combination[n]='[' candlenumber[i] ',' candlenumber[j] ',' candlenumber[k] ']';
n ;
}
}
}
}
return(true);
}
基于燭條集合創(chuàng)建形態(tài),由 GetCandleCombination() 方法執(zhí)行。 該方法的目的是基于所選燭條的序列號顯示所有可能的簡單燭條組合,有或沒有反復(fù),且考慮了形態(tài)部分中所選的燭條數(shù)大小。
所有組合都寫入字符串?dāng)?shù)組 m_total_combitaion[],并在 BuildingAutoSearchTable() 方法中將數(shù)據(jù)添加到結(jié)果表格之中。
第二個方法在 BuildingAutoSearchTable() 之后調(diào)用,負(fù)責(zé)根據(jù)生成的形態(tài)結(jié)果列表計(jì)算和顯示其他數(shù)據(jù)。 我們更詳細(xì)地考察 GetPatternType() 方法 - 它在第一篇文章中用于計(jì)算預(yù)定義形態(tài),但它已被簡化。 此任務(wù)的目的是識別圖表上的預(yù)設(shè)形態(tài),并進(jìn)行分析。 由于此方法用來搜索已存在的形態(tài),以及所生成的形態(tài),因此實(shí)現(xiàn)了方法重載:
//--- 識別形態(tài)
bool GetPatternType(const string symbol);
bool GetPatternType(const string symbol,string &total_combination[]);
在第二個變體中,我們使用 先前創(chuàng)建的含有所生成形態(tài)的字符串?dāng)?shù)據(jù)數(shù)組。 該方法的目的是識別圖表上生成的任何形態(tài),對其進(jìn)行評估并計(jì)算其效率。 在第一篇文章的 任務(wù)定義 部分中提供了該思路和算法描述。 因此,我們現(xiàn)在不再贅述。
評估所發(fā)現(xiàn)形態(tài)效率早前是用數(shù)組,我們?yōu)樯闲汹厔莺拖滦汹厔萏砑恿祟悇e評估 A、B 和 C。 在本文中,我們將數(shù)組轉(zhuǎn)換為結(jié)構(gòu)。 這樣可以縮短生成的代碼。 該結(jié)構(gòu)如下:
struct RATING_SET
{
int a_uptrend;
int b_uptrend;
int c_uptrend;
int a_dntrend;
int b_dntrend;
int c_dntrend;
};
對于我們的任務(wù),每個生成的形態(tài)我們都需要這組估計(jì)。 所以,在方法的開頭聲明 RATING_SET 結(jié)構(gòu)數(shù)組。 數(shù)組大小對應(yīng)于所生成形態(tài)數(shù)量,或字符串?dāng)?shù)組 m_total_combitaion[] 的大小。
RATING_SET ratings[];
//---
total_patterns=ArraySize(total_combination);
...
ArrayResize(ratings,total_patterns);
此數(shù)組存儲所有生成的形態(tài),但這些形態(tài)在表格結(jié)果的第一列中會以字符串顯現(xiàn)。 因此,下一階段是從每個字符串中提取使用過的簡單燭條形態(tài)的索引,并將它們從 CANDLE_STRUCTURE 轉(zhuǎn)換為燭條類型。
struct CANDLE_STRUCTURE
{
double open,high,low,close; // OHLC
TYPE_TREND trend; //趨勢
bool bull; //多頭
double bodysize; //空頭
TYPE_CANDLESTICK type; //燭條類型
};
為此,我們將進(jìn)行一些轉(zhuǎn)換。 此外,我們將考慮另一種方法,該方法有助于將燭條索引轉(zhuǎn)換為其類型。
//---
for(int i=0;i<total_patterns;i )
{
StringReplace(total_combination[i],'[','');
StringReplace(total_combination[i],']','');
if(m_pattern_size>1)
{
ushort sep=StringGetCharacter(',',0);
StringSplit(total_combination[i],sep,elements);
}
ZeroMemory(ratings[i]);
m_pattern_total[i]=0;
if(m_pattern_size==1)
IndexToPatternType(cand1[i],(int)total_combination[i]);
else if(m_pattern_size==2)
{
IndexToPatternType(cand1[i],(int)elements[0]);
IndexToPatternType(cand2[i],(int)elements[1]);
}
else if(m_pattern_size==3)
{
IndexToPatternType(cand1[i],(int)elements[0]);
IndexToPatternType(cand2[i],(int)elements[1]);
IndexToPatternType(cand3[i],(int)elements[2]);
}
}
循環(huán)遍歷所生成形態(tài)的每個字符串值,刪除方括號,基于分隔符 “,” 應(yīng)用 StringSplit(),并向 elements[] 數(shù)組添加信息。 請注意,此過程適用于由超過 1 根燭條組成的形態(tài),因?yàn)閷τ谝桓鶢T條,不會有逗號,我們只需要刪除方括號。 現(xiàn)在我們考察 IndexToPatternType() 方法,我們輸入 CANDLE_STRUCTURE 來填充和處理所生成形態(tài)數(shù)組中的數(shù)據(jù)。
void CProgram::IndexToPatternType(CANDLE_STRUCTURE &res,const int index)
{
//--- 長燭 - 多頭
if(index==1)
{
res.bull=true;
res.type=CAND_LONG;
}
//--- 長燭 - 空頭
else if(index==2)
{
res.bull=false;
res.type=CAND_LONG;
}
//--- 短燭 - 多頭
else if(index==3)
{
res.bull=true;
res.type=CAND_SHORT;
}
//--- 短燭 - 空頭
else if(index==4)
{
res.bull=false;
res.type=CAND_SHORT;
}
//--- 尖頂 - 多頭
else if(index==5)
{
res.bull=true;
res.type=CAND_SPIN_TOP;
}
//--- 尖頂 - 空頭
else if(index==6)
{
res.bull=false;
res.type=CAND_SPIN_TOP;
}
//--- 十字星
else if(index==7)
{
res.bull=true;
res.type=CAND_DOJI;
}
//--- Marubozu - 多頭
else if(index==8)
{
res.bull=true;
res.type=CAND_MARIBOZU;
}
//--- Marubozu - 空頭
else if(index==9)
{
res.bull=false;
res.type=CAND_MARIBOZU;
}
//--- 錘子 - 多頭
else if(index==10)
{
res.bull=true;
res.type=CAND_HAMMER;
}
//--- 錘子 - 空頭
else if(index==11)
{
res.bull=false;
res.type=CAND_HAMMER;
}
}
根據(jù)形態(tài)大小,填充一個、兩個或三個 CANDLE_STRUCTURE:cand1,cand2,cand3。 參見以下代碼:
if(m_pattern_size==1)
IndexToPatternType(cand1[i],(int)total_combination[i]);
else if(m_pattern_size==2)
{
IndexToPatternType(cand1[i],(int)elements[0]);
IndexToPatternType(cand2[i],(int)elements[1]);
}
else if(m_pattern_size==3)
{
IndexToPatternType(cand1[i],(int)elements[0]);
IndexToPatternType(cand2[i],(int)elements[1]);
IndexToPatternType(cand3[i],(int)elements[2]);
}
無論圖表上的形態(tài)大小如何,都可以立即分析所需數(shù)量的燭條。
對于單燭條形態(tài),在每種特定情況下,只有一根燭條用于分析和計(jì)算,而整個集合將用于 2 燭條和 3 燭條形態(tài)。 例如,若樣本范圍為 2000 燭條,則對于 1 燭條形態(tài),該集合將由第 2000 根燭條組成。 若是兩根燭條,集合由第 2000 根和第 1999 根組成,依此類推。
接下來,我們考察 GetPatternType() 方法的以下片段,該方法負(fù)責(zé)查找圖表上的每個生成的形態(tài)。
//---
for(int i=m_range_total2;i>5;i--)
{
if(m_pattern_size==1)
{
//--- 獲取當(dāng)前的燭條類型
GetCandleType(symbol,cur_cand,m_timeframe2,i); // Current candlestick
//---
for(int j=0;j<total_patterns;j )
{
if(cur_cand.type==cand1[j].type && cur_cand.bull==cand1[j].bull)
{
m_pattern_total[j] ;
GetCategory(symbol,i-3,ratings[j],m_timeframe2);
}
}
}
else if(m_pattern_size==2)
{
//--- 獲取當(dāng)前的燭條類型
GetCandleType(symbol,prev_cand,m_timeframe2,i); // 前根燭條
GetCandleType(symbol,cur_cand,m_timeframe2,i-1); // 當(dāng)前燭條
//---
for(int j=0;j<total_patterns;j )
{
if(cur_cand.type==cand1[j].type && cur_cand.bull==cand1[j].bull &&
prev_cand.type==cand2[j].type && prev_cand.bull==cand2[j].bull)
{
m_pattern_total[j] ;
GetCategory(symbol,i-4,ratings[j],m_timeframe2);
}
}
}
else if(m_pattern_size==3)
{
//--- 獲取當(dāng)前的燭條類型
GetCandleType(symbol,prev_cand2,m_timeframe2,i); // 前根燭條
GetCandleType(symbol,prev_cand,m_timeframe2,i-1); // 前根燭條
GetCandleType(symbol,cur_cand,m_timeframe2,i-2); // 當(dāng)前燭條
//---
for(int j=0;j<total_patterns;j )
{
if(cur_cand.type==cand1[j].type && cur_cand.bull==cand1[j].bull &&
prev_cand.type==cand2[j].type && prev_cand.bull==cand2[j].bull &&
prev_cand2.type==cand3[j].type && prev_cand2.bull==cand3[j].bull)
{
m_pattern_total[j] ;
GetCategory(symbol,i-5,ratings[j],m_timeframe2);
}
}
}
}
正如我們在上面的代碼中看到的那樣,循環(huán)處于最開始,停在了第六根燭條。 為什么? 在第一篇文章中我們提到,為了分析形態(tài)效率,我們需要判定形態(tài)形成后價(jià)格的走向,并找出形態(tài)預(yù)測的內(nèi)容,預(yù)測頻率和概率是多少。 為此評估,我們要在形態(tài)之后三根燭條內(nèi)實(shí)施價(jià)格走勢分析。 當(dāng)前的零號燭條不參與分析,因?yàn)樗形赐瓿伞?nbsp;

圖例 9 形態(tài)效率評估的計(jì)算。
三燭條形態(tài)如圖例 9 所示。 為了評估它的效率,除了零號燭條之外我們還需要三根燭條。 所以,為了滿足當(dāng)前形態(tài)的這些條件,形態(tài)內(nèi)第一根燭條的的最小索引可以為 6。
在搜索形態(tài)之后,計(jì)算其數(shù)量,并按 A、B、C 類別進(jìn)行評估,我們需要處理收到數(shù)據(jù)并將結(jié)果添加到表格中。 這些計(jì)算在 CoefCalculation() 方法中執(zhí)行。
//---
for(int i=0;i<total_patterns;i )
CoefCalculation(m_table2,i,ratings[i],m_pattern_total[i]);
方法的參數(shù)是:
- m_table2 — 指向每個所生成形態(tài)計(jì)算結(jié)果的表格鏈接。
- i — 表格所在行。
- ratings[i] — RATING_SET 結(jié)構(gòu)數(shù)組,其中包含每個形態(tài)基于評級的一組類別。
- m_pattern_total[i] — 包含每種類型已發(fā)現(xiàn)形態(tài)數(shù)量的數(shù)組。
我們更詳細(xì)地考察該方法。
// ------------------------------------------------------------------
//| 計(jì)算效率評估系數(shù) |
// ------------------------------------------------------------------
bool CProgram::CoefCalculation(CTable &table,const int row,RATING_SET &rate,int found)
{
double p1,p2,k1,k2;
int sum1=0,sum2=0;
sum1=rate.a_uptrend rate.b_uptrend rate.c_uptrend;
sum2=rate.a_dntrend rate.b_dntrend rate.c_dntrend;
//---
p1=(found>0)?NormalizeDouble((double)sum1/found*100,2):0;
p2=(found>0)?NormalizeDouble((double)sum2/found*100,2):0;
k1=(found>0)?NormalizeDouble((m_k1*rate.a_uptrend m_k2*rate.b_uptrend m_k3*rate.c_uptrend)/found,3):0;
k2=(found>0)?NormalizeDouble((m_k1*rate.a_dntrend m_k2*rate.b_dntrend m_k3*rate.c_dntrend)/found,3):0;
table.SetValue(1,row,(string)found);
table.SetValue(2,row,(string)((double)found/m_range_total2*100),2);
table.SetValue(3,row,(string)p1,2);
table.SetValue(4,row,(string)p2,2);
table.SetValue(5,row,(string)k1,2);
table.SetValue(6,row,(string)k2,2);
//--- 更新表格
table.Update(true);
table.GetScrollVPointer().Update(true);
table.GetScrollHPointer().Update(true);
return(true);
}
從方法實(shí)現(xiàn)中可以看出,由于使用了結(jié)構(gòu),我們可以清晰地看到如何計(jì)算形態(tài)分析系數(shù)。
作為示例,我們將使用不同的參數(shù)測試一些生成的形態(tài)。
步驟 1. 選擇簡單燭條模型。
首先,我們需要在用過的燭條部分選擇所有可能的簡單燭條模型,設(shè)置 “有反復(fù)”,并將 “形態(tài)中的燭條數(shù)量” 設(shè)為一。 以點(diǎn)數(shù)為單位的閾值趨勢值將設(shè)置為 200。 這是設(shè)置:

圖例 10 用于分析所生成形態(tài)的第一個設(shè)置步驟。
現(xiàn)在導(dǎo)航到 “AutoSearch” 選項(xiàng)卡,在搜索框中鍵入 Major,然后單擊搜索。 然后將時間幀設(shè)置為 Н1,并選擇貨幣對 GBPUSD。 以下是測試結(jié)果。

圖例 11 測試結(jié)果生成一根燭條形態(tài)。
選擇六種最常見的燭條類型。 這些是降序 1,2,5,6,3,4。
步驟 2. 測試雙燭條形態(tài)。
現(xiàn)在基于簡單類型形成兩根燭條形態(tài)。 導(dǎo)航到 “設(shè)置” 選項(xiàng)卡,然后取消曾選中的 7 到 11 的框。 這次我們設(shè)置 “無反復(fù)” 模式,并將 “形態(tài)中的蠟燭數(shù)” 設(shè)置為 2。 上述配置如圖例 12 所示。

圖例 12 測試生成的雙燭條形態(tài)的配置。
導(dǎo)航回到自動搜索,并點(diǎn)擊 GBPUSD。 按選擇燭條生成各種組合,并提供其評級。 但如果 “閾值趨勢值” 較低,特別是在更高的時間幀內(nèi),價(jià)格走勢結(jié)果通常幾乎相同。 通過增加閾值,可以為形態(tài)搜索設(shè)置更嚴(yán)格的條件。 例如,下面是閾值等于 400 的結(jié)果:

圖例 13 趨勢閾值增加的測試結(jié)果。
在獲得的結(jié)果中,我試圖在一個方向上找到一個大的價(jià)格走勢,而在反方向上找到若干較少的走勢。 從圖例 13 中可以看出,這種狀況遇到了兩次:[1,4] 和 [2,6]。 這些形態(tài)是長燭(多頭)— 短燭(空頭)和長燭(空頭)— 尖頂(空頭)。 第二種形態(tài)變體是最優(yōu)選擇,因?yàn)槠涑霈F(xiàn)的頻率幾乎高出一倍。
現(xiàn)在我們測試三燭條形態(tài)。 有了所有可能的簡單模型選項(xiàng),我們得到了太多的形態(tài)變體,所以我們將只使用 4 種類型,這在以前的測試中經(jīng)常遇到 — 1,2,5,6。 正確配置的 “設(shè)置” 選項(xiàng)卡如下所示:

圖例 14 測試生成的三燭條形態(tài)的配置。
閾值趨勢值仍然等于 400。 然后打開 “AutoSearch” 選項(xiàng)卡,再次單擊 GBPUSD。 這里使用了選擇表現(xiàn)良好形態(tài)的相同原則:在一個方向上的價(jià)格走勢比在反方向上超出許多。 這可以從效率系數(shù)中看出。 例如,連續(xù)兩次我遇到非常有趣的結(jié)果,具有非常好的系數(shù)和概率參數(shù)。

圖例 15 產(chǎn)生的三燭條形態(tài)測試結(jié)果。
這些形態(tài)是 [2,5,2] 和下一個 [2,5,5]:長燭(空頭)— 尖頂(多頭)— 長燭(空頭)和長燭(空頭)— 尖頂(多頭)— 尖頂(多頭)。 第一個燭條形態(tài)顯示出上型趨勢的高概率,和巨大的效率系數(shù)。 第二個則具有良好的單向概率,但效率系數(shù)略低。
大量的參數(shù)組合可以提供其他有趣的結(jié)果。 測試時,建議不要同時使用所有 11 種燭條類型,因?yàn)閿?shù)據(jù)處理可能需要很長時間。 所分析形態(tài)的最大可能組合等于 1463,未考慮樣本范圍,時間幀,趨勢閾值和簡單燭條類型的個別設(shè)置。 如此大量的分析需要花費(fèi)很多時間。