量化交易軟件:如何分析圖表中所選擇信號的交易
概述
新信號,免費或付費,會永久性地出現(xiàn)在信號 服務(wù)中。 赫茲量化團(tuán)隊注意到可以在不退出終端的情況下使用該服務(wù)。 所有剩余的工作就是選擇可接受風(fēng)險范圍能夠產(chǎn)生最高利潤的信號。 很久以前就討論過這個問題。 曾提出過通過指定標(biāo)準(zhǔn) [1] 自動選擇信號的方法。 然而,傳統(tǒng)觀點認(rèn)為一張圖片勝過千言萬語。 在本文中,我提議研究和分析品種圖表中所選信號的交易歷史。 或許,這種方法可以令我們更好地理解交易策略和風(fēng)險評估。

編輯切換為居中
1. 為我們未來的工作設(shè)定目標(biāo)
我好像聽到您難過了: '如果終端已經(jīng)提供了在圖表中顯示交易歷史的能力,為什么還要重新創(chuàng)建輪子呢? 我的意思是,只需按下終端中的按鈕即可選擇所需的信號。'

編輯
在此之后,根據(jù)所使用品種信號的數(shù)量,在終端中打開新窗口,并在交易上做出標(biāo)記。 當(dāng)然,分頁圖表以及在其中搜索交易是相當(dāng)費力的活動。 甚或,在不同圖表中進(jìn)行的交易可能會在時間上重合,且在分別分析每個圖表時您無法看到。 在此階段,我赫茲量化們將嘗試將我們的部分工作自動化。
為了辨別我們從圖表獲得的所需分析的品種,我們必須清晰地了解我們需要的最終結(jié)果。 以下是我最終想要的基本項目:
查看信號在不同品種上的均勻性如何;
了解如何分配資金的負(fù)荷,以及同時可開倉數(shù)量;
如果信號同時開多筆倉位,那么它們是否為對沖,亦或增加了資金的負(fù)荷;
在什么時刻以及在哪些品種上出現(xiàn)了最大的縮水; 以及
在什么時刻實現(xiàn)最大的盈利。
2. 收集交易統(tǒng)計數(shù)據(jù)
2.1. 用于保存訂單信息的類
因此,我赫茲量化們選擇所需的信號并在圖表中顯示其交易歷史。 然后收集我們將要分析的初始數(shù)據(jù)。 為了記錄每筆訂單的信息,我們基于 CObject 類創(chuàng)建 COrder 類。 在這個類的變量中,我們保存訂單號,交易類型和手?jǐn)?shù),交易價格,操作類型 (入場/出場),訂單開倉時間,當(dāng)然還有品名。
class COrder : public CObject ?{ private: ? long ? ? ? ? ? ? ? ? l_Ticket; ? double ? ? ? ? ? ? ? d_Lot; ? double ? ? ? ? ? ? ? d_Price; ? ENUM_POSITION_TYPE ? e_Type; ? ENUM_DEAL_ENTRY ? ? ?e_Entry; ? datetime ? ? ? ? ? ? dt_OrderTime; ? string ? ? ? ? ? ? ? s_Symbol; ? public: ? ? ? ? ? ? ? ? ? ? ? ?COrder(); ? ? ? ? ? ? ? ? ? ? ? ~COrder(); ? bool ? ? ? ? ? ? ? ? Create(string symbol, long ticket, double volume, double price, datetime time, ENUM_POSITION_TYPE type); //--- ? string ? ? ? ? ? ? ? Symbol(void) ? const { ?return s_Symbol; ? ? } ? long ? ? ? ? ? ? ? ? Ticket(void) ? const { ?return l_Ticket; ? ? } ? double ? ? ? ? ? ? ? Volume(void) ? const { ?return d_Lot; ? ? ? ?} ? double ? ? ? ? ? ? ? Price(void) ? ?const { ?return d_Price; ? ? ?} ? datetime ? ? ? ? ? ? Time(void) ? ? const { ?return dt_OrderTime; } ? ENUM_POSITION_TYPE ? Type(void) ? ? ? ? ? { ?return e_Type; ? ? ? } ? ENUM_DEAL_ENTRY ? ? ?DealEntry(void)const { ?return e_Entry; ? ? ?} ? void ? ? ? ? ? ? ? ? DealEntry(ENUM_DEAL_ENTRY value) { ?e_Entry=value; } //--- 操縱文件的方法 ? virtual bool ? ? ? ? Save(const int file_handle); ? virtual bool ? ? ? ? Load(const int file_handle); //--- ? //--- 比較對象的方法 ? virtual int ? ? ? ? ?Compare(const CObject *node,const int mode=0) const; ?};
伴隨數(shù)據(jù)訪問函數(shù),我們向訂單類添加了操縱文件函數(shù)以便保存和隨后讀取數(shù)據(jù),還有比較類似的函數(shù),因為我們將需要對訂單進(jìn)行排序。
為了與訂單進(jìn)行比較,我赫茲量化們需要重新編寫虛函數(shù) Compare。 這是基類的函數(shù),用于比較 CObject 對象。 所以,對象 CObject 的鏈接和排序方法將作為參數(shù)傳遞給它。 我們僅在一個方向上對訂單進(jìn)行排序,即按照執(zhí)行日期升序,因此我們不會在函數(shù)代碼中使用參數(shù) "mode"。 但是,對于通過鏈接獲得的對象 COrder,我們必須首先將其降低到相關(guān)類型。 之后,我們比較所獲訂單的日期和當(dāng)前訂單的日期。 如果所獲訂單更老,則返回 "-1"。 如果它比較新, 則返回 "1"。 如果執(zhí)行訂單的日期相等,則函數(shù)將返回 "0"。
int COrder::Compare(const CObject *node,const int mode=0) const ?{ ? const COrder *temp=GetPointer(node); ? if(temp.Time()>dt_OrderTime) ? ? ?return -1; //--- ? if(temp.Time()<dt_OrderTime) ? ? ?return 1; //--- ? return 0; ?}
2.2. 從圖表中收集信息
為了處理訂單,我們基于 CArrayObj 類創(chuàng)建 COrdersCollection 類。 將在其中收集和處理信息。 為了存儲數(shù)據(jù),我們將聲明一個對象實例直接處理特定訂單,以及一個用于存儲所用品種列表的數(shù)組。 我們將使用基類函數(shù)存儲訂單數(shù)組。
class COrdersCollection : public CArrayObj ?{ private: ? COrder ? ? ? ? ? ?*Temp; ? string ? ? ? ? ? ?ar_Symbols[]; ? public: ? ? ? ? ? ? ? ? ? ? COrdersCollection(); ? ? ? ? ? ? ? ? ? ?~COrdersCollection(); //--- 初始化 ? bool ? ? ? ? ? ? ?Create(void); //--- 加入一筆訂單 ? bool ? ? ? ? ? ? ?Add(COrder *element); //--- 訪問數(shù)據(jù) ? int ? ? ? ? ? ? ? Symbols(string &array[]); ? bool ? ? ? ? ? ? ?GetPosition(const string symbol, const datetime time, double &volume, double &price, ENUM_POSITION_TYPE &type); ? datetime ? ? ? ? ?FirstOrder(const string symbol=NULL); ? datetime ? ? ? ? ?LastOrder(const string symbol=NULL); //--- 獲取時間序列 ? bool ? ? ? ? ? ? ?GetTimeSeries(const string symbol, const datetime start_time, const datetime end_time, const int direct, ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? double &balance[], double &equity[], double &time[], double &profit, double &loss,int &long_trades, int &short_trades); //--- ? void ? ? ? ? ? ? ?SetDealsEntry(void); ?};
函數(shù) 'Create' 直接負(fù)責(zé)收集數(shù)據(jù)。 在方法實體內(nèi),我們將安排一個循環(huán)來搜索終端中已打開的所有圖表。 我們將在每個圖表中搜索 OBJ_ARROW_BUY 和 OBJ_ARROW_SELL 等圖形對象。
bool COrdersCollection::Create(void) ?{ ? long chart=ChartFirst(); ? while(chart>0) ? ? { ? ? ?int total_buy=ObjectsTotal(chart,0,OBJ_ARROW_BUY); ? ? ?int total_sell=ObjectsTotal(chart,0,OBJ_ARROW_SELL); ? ? ?if((total_buy+total_sell)<=0) ? ? ? ?{ ? ? ? ? chart=ChartNext(chart); ? ? ? ? continue; ? ? ? ?}
如果在圖表中找到了對象,那么我赫茲量化們將圖表品種添加到品種數(shù)組中 (不過,我們會預(yù)先檢查這些品種是否不在已保存的品種中)。
? ? ?int symb=ArraySize(ar_Symbols); ? ? ?string symbol=ChartSymbol(chart); ? ? ?bool found=false; ? ? ?for(int i=0;(i<symb && !found);i++) ? ? ? ? if(ar_Symbols[i]==symbol) ? ? ? ? ? { ? ? ? ? ? ?found=true; ? ? ? ? ? ?symb=i; ? ? ? ? ? ?break; ? ? ? ? ? } ? ? ?if(!found) ? ? ? ?{ ? ? ? ? if(ArrayResize(ar_Symbols,symb+1,10)<=0) ? ? ? ? ? ?return false; ? ? ? ? ar_Symbols[symb]=symbol; ? ? ? ?}
然后我們安排從圖表中收集交易信息,并存儲到數(shù)據(jù)數(shù)組。 注意: 圖形對象是我們唯一的交易信息來源。 從對象參數(shù)里,我們只能得到交易的時間和價格。 我們必須從對象名稱的文本字符串中獲取所有其它詳細(xì)信息。

編輯
在圖片中,您可以看到對象名稱包含交易中的所有數(shù)據(jù),以空格分隔。 我們利用這點并將字符串用空格切分成一個字符串元素數(shù)組。 然后,我赫茲量化們從相關(guān)元素中減少信息量,并保存所需的數(shù)據(jù)類型。 收集信息后,我們轉(zhuǎn)到下一個圖表。
? ? ?int total=fmax(total_buy,total_sell); ? ? ?for(int i=0;i<total;i++) ? ? ? ?{ ? ? ? ? if(i<total_buy) ? ? ? ? ? { ? ? ? ? ? ?string name=ObjectName(chart,i,0,OBJ_ARROW_BUY); ? ? ? ? ? ?datetime time=(datetime)ObjectGetInteger(chart,name,OBJPROP_TIME); ? ? ? ? ? ?StringTrimLeft(name); ? ? ? ? ? ?StringTrimRight(name); ? ? ? ? ? ?StringReplace(name,"#",""); ? ? ? ? ? ?string split[]; ? ? ? ? ? ?StringSplit(name,' ',split); ? ? ? ? ? ?Temp=new COrder; ? ? ? ? ? ?if(CheckPointer(Temp)!=POINTER_INVALID) ? ? ? ? ? ? ?{ ? ? ? ? ? ? ? if(Temp.Create(ar_Symbols[symb],StringToInteger(split[1]),StringToDouble(split[3]),StringToDouble(split[6]),time,POSITION_TYPE_BUY)) ? ? ? ? ? ? ? ? ?Add(Temp); ? ? ? ? ? ? ?} ? ? ? ? ? } //--- ? ? ? ? if(i<total_sell) ? ? ? ? ? { ? ? ? ? ? ?string name=ObjectName(chart,i,0,OBJ_ARROW_SELL); ? ? ? ? ? ?datetime time=(datetime)ObjectGetInteger(chart,name,OBJPROP_TIME); ? ? ? ? ? ?StringTrimLeft(name); ? ? ? ? ? ?StringTrimRight(name); ? ? ? ? ? ?StringReplace(name,"#",""); ? ? ? ? ? ?string split[]; ? ? ? ? ? ?StringSplit(name,' ',split); ? ? ? ? ? ?Temp=new COrder; ? ? ? ? ? ?if(CheckPointer(Temp)!=POINTER_INVALID) ? ? ? ? ? ? ?{ ? ? ? ? ? ? ? if(Temp.Create(ar_Symbols[symb],StringToInteger(split[1]),StringToDouble(split[3]),StringToDouble(split[6]),time,POSITION_TYPE_SELL)) ? ? ? ? ? ? ? ? ?Add(Temp); ? ? ? ? ? ? ?} ? ? ? ? ? } ? ? ? ?} ? ? ?chart=ChartNext(chart); ? ? }
圖形標(biāo)記沒有每筆交易是開倉還是平倉的信息。 這就是為什么在保存交易信息時此字段仍未填寫的原因。 現(xiàn)在,從圖表中收集了所有標(biāo)記后,赫茲量化調(diào)用函數(shù) SetDealsEntry 來添加缺失的數(shù)據(jù)。
? SetDealsEntry();