期貨量化:赫茲量化中遞歸下降解析器
在自動(dòng)執(zhí)行交易任務(wù)時(shí),可能需要在其執(zhí)行階段提供計(jì)算算法的靈活性。 例如,當(dāng)微調(diào)程序以閉合(編譯)模式分布時(shí),我們可以從眾多可能的組合中選擇目標(biāo)函數(shù)類型。 特別是在優(yōu)化智能交易系統(tǒng)或快速評(píng)估指標(biāo)原型時(shí),這很有用。 除了更改對(duì)話框中的參數(shù)之外,用戶還可以更改計(jì)算公式。 在這種情況下,我們只需從其文本表達(dá)形式計(jì)算其數(shù)學(xué)表達(dá)式,而無(wú)需更改 MQL 程序代碼。
可以通過(guò)各種解析器來(lái)解決此任務(wù),這些解析器可以即時(shí)解釋公式,將其“編譯”為語(yǔ)法樹(shù),生成所謂的字節(jié)碼(計(jì)算指令序列),進(jìn)而執(zhí)行從而得出計(jì)算結(jié)果 。 在本文中,我們將研究幾種類型的解析器和表達(dá)式計(jì)算方法。
解析器基類(AbstractExpressionProcessor 模板)
這是模板類,由于表達(dá)式分析結(jié)果不僅可以是標(biāo)量值,而且還可以是描述表達(dá)式語(yǔ)法的節(jié)點(diǎn)樹(shù)(特殊類的對(duì)象)。 稍后我們會(huì)研究如何完成此操作,以及這樣做的目的是什么。
首先,類對(duì)象存儲(chǔ)表達(dá)式(_expression),其長(zhǎng)度(_length),讀取字符串(_index)時(shí)的當(dāng)前光標(biāo)位置,和當(dāng)前符號(hào)(_token)。 它還預(yù)留了指示表達(dá)式中錯(cuò)誤的變量(_failed),和數(shù)值比較精度(_precision)。
?template<typename T> ?class AbstractExpressionProcessor ?{ ? ?protected: ? ? ?string _expression; ? ? ?int _index; ? ? ?int _length; ? ? ?ushort _token; ? ? ? ?bool _failed; ? ? ?double _precision;
提供了存儲(chǔ)變量和鏈接的特殊表,但是稍后我們將研究相關(guān)的 VariableTable 和 FunctionTable 類。
? ? ?VariableTable *_variableTable; ? ? ?FunctionTable _functionTable;
這些表是由 “key=value” 對(duì)組成的關(guān)鍵字=數(shù)值對(duì),其中關(guān)鍵字是變量或函數(shù)名稱的字符串,而數(shù)值則是 double(對(duì)于變量),或 functor 對(duì)象(對(duì)于表) 。
變量表由引用描述,因?yàn)楸磉_(dá)式不能包含變量。 對(duì)于函數(shù)表,解析器始終含有最少的內(nèi)置函數(shù)集合(用戶可以擴(kuò)展),這就是為什么此表由已有對(duì)象表示的原因。
標(biāo)準(zhǔn)函數(shù)表是在方法中填充:
? ? ?virtual void registerFunctions();
下一章節(jié)介紹的函數(shù)執(zhí)行的子任務(wù)通用于各種解析器,例如切換到下一個(gè)字符,對(duì)照期望值檢查字符(如果不匹配則顯示錯(cuò)誤),順序讀取滿足格式要求的數(shù)字, 以及一些用于字符分類的靜態(tài)輔助方法。
? ? ?bool _nextToken(); ? ? ?void _match(ushort c, string message, string context = NULL); ? ? ?bool _readNumber(string &number); ? ? ?virtual void error(string message, string context = NULL, const bool warning = false); ? ? ? ? ? ?static bool isspace(ushort c); ? ? ?static bool isalpha(ushort c); ? ? ?static bool isalnum(ushort c); ? ? ?static bool isdigit(ushort c);
所有這些函數(shù)都在基類中定義,尤其是:
?template<typename T> ?bool AbstractExpressionProcessor::_nextToken() ?{ ? ?_index++; ? ?while(_index < _length && isspace(_expression[_index])) _index++; ? ?if(_index < _length) ? ?{ ? ? ?_token = _expression[_index]; ? ? ?return true; ? ?} ? ?else ? ?{ ? ? ?_token = 0; ? ?} ? ?return false; ?} ? ?template<typename T> ?void AbstractExpressionProcessor::_match(ushort c, string message, string context = NULL) ?{ ? ?if(_token == c) ? ?{ ? ? ?_nextToken(); ? ?} ? ?else if(!_failed) // prevent chained errors ? ?{ ? ? ?error(message, context); ? ?} ?} ? ?template<typename T> ?bool AbstractExpressionProcessor::_readNumber(string &number) ?{ ? ?bool point = false; ? ?while(isdigit(_token) || _token == '.') ? ?{ ? ? ?if(_token == '.' && point) ? ? ?{ ? ? ? ?error("Too many floating points", __FUNCTION__); ? ? ? ?return false; ? ? ?} ? ? ?number += ShortToString(_token); ? ? ?if(_token == '.') point = true; ? ? ?_nextToken(); ? ?} ? ?return StringLen(number) > 0; ?}