最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會員登陸 & 注冊

股票量化交易軟件:使用限價訂單替代止盈且無需修改 EA 的原始代碼

2023-07-14 15:32 作者:bili_45793681098  | 我要投稿

在各種論壇中,用戶批評赫茲股票量化的市場止盈價位性能。 這樣的帖子也可以在本網(wǎng)站的論壇里找到。 用戶撰寫了許多在執(zhí)行止盈期間滑點對結算結果的負面影響。 作為備選方案,一些人建議使用限價訂單來取代標準止盈。

另一方面,與標準止盈相比,采用限價訂單允許交易者實現(xiàn)部分和逐級平倉的算法,因為在限價訂單中,您可以指定不同于實際持倉量的交易量。 在本文中,我想提供一種能夠實現(xiàn)此類止盈的替代選項。

1. 一般觀點

我認為,沒有必要爭論哪種方案更好 — 內置的止盈或取代它的限價訂單。 每個交易者都應該根據(jù)他們的策略原則和需求來解決這個問題。 本文僅提供一種可能的解決方案。

在開發(fā)限價訂單系統(tǒng)之前,赫茲股票量化研究一下在設計算法時應該注意的一些方面。

赫茲股票量化應記住的主要事件是,止盈是指平倉的訂單。 這似乎是不言而喻的,但所有人都習慣于由終端和系統(tǒng)來執(zhí)行這一任務。 由于我們決定替換設定止盈的系統(tǒng),我們應對其負全部維護責任。

我到底在說什么? 一筆持倉不僅可以通過止盈平倉,而且可以通過止損或交易者自行決定平倉(通常運行一些 EA 以市價平倉)。 這意味著赫茲股票量化的系統(tǒng)應該能跟蹤市場中是否存在相應持倉,并在無持倉或出現(xiàn)任何原因時立即刪除限價掛單。 否則,與標準止盈激活期間的滑點相比,此方法可能會在不期望的情況下開倉,從而導致更大的損失。

此外,持倉量可以部分平倉,也可以增加(對于凈持賬戶)。 所以,重要的是不僅要跟蹤有效持倉,還要跟蹤其倉量。 如果持倉量已變化,則應立即修改限價掛單。

另一層面則涉及對沖系統(tǒng)操作。 該系統(tǒng)能夠進行持倉的單獨結算,并允許單一品種同時開多倉。 這意味著激活限價訂單不會將現(xiàn)有持倉平倉。 代之,它會開一筆新倉。 因此,在觸發(fā)限價訂單后,赫茲股票量化需要以相反的倉位進行平倉。

另一個可能的問題是掛單的止盈。 在這種情況下,我們應該確保在處理訂單之前不會觸發(fā)止盈。 第一反應,是可以使用 stop-limit 掛單。 例如,赫茲股票量化可以同時放置 sell stop 掛單和 buy stop 限價掛單。 但是系統(tǒng)不允許我們使用 sell limit 執(zhí)行類似的操作。 這會引發(fā)隨后一系列限價止盈的跟蹤掛單激活的問題。 反過來,跟蹤程序內的掛單激活并放置一筆無止盈掛單,有可能導致開倉失控。 結果就是,價格也許觸及止盈并反轉。 程序失卻控制,不允許平倉,最終造成虧損。

我個人的解決方案是在指定標準止盈時放置掛單。 在開倉后,放置限價掛單替代止盈,并將止盈設置為零。 此選項可確保我們不會失去對事態(tài)的控制。 如果程序失去與服務器的連接,則系統(tǒng)將激活訂單止盈。 在此情況下,由負值滑點引起的可能虧損低于失控而導致的虧損。

另一個問題是改變先前設定的止盈。 通常,在運用不同的策略時,您必須跟蹤并調整持倉的止盈。 我們有兩種選擇。

  1. 如果我們修改這樣的 EA 代碼,那么為了在代碼中不必搜索所有可能的選項來變更止盈,我們僅需調用我們的類方法來替換調用 OrderSend 函數(shù),在類方法中我們已檢查了是否存在先前設置的限價訂單,以及它是否對應于新價位。 如有必要,修改先前下達的訂單,或者,如果先前下達的限價訂單符合新需求,則忽略該命令。

  2. 我們運用采購的 EA,但我們無法訪問其代碼; 我們的程序不會開倉,只會取代止盈。 在這種情況下,很高概率可能會為我們已設置限價單的持倉設置了止盈。 這意味著我們應加強現(xiàn)有限價訂單的相關檢查并調整它們,同時將止盈字段設置為零。

此外,赫茲股票量化應該跟蹤自當前價格設置掛單的最小距離,以及經(jīng)紀商設置的凍結交易的距離。 如果前者同樣應用在設置系統(tǒng)止盈,則凍結距離可能會拖累,因為在小于其范圍內刪除或修改用于平倉的限價掛單是不可能的。 不幸的是,這種風險不僅應該在構建系統(tǒng)時考慮,還應該在運用時加以考慮,因為它不依賴于系統(tǒng)的算法。

2. 實現(xiàn) "持倉 - 限制訂單" 鏈接的原理

正如我之前已經(jīng)提到的,跟蹤持倉的狀態(tài)并搜索與之匹配的限價止盈是必要的。 我們來看看如何實現(xiàn)這一點。 首先,赫茲股票量化需要判斷在什么時間點我們需要進行控制以避免終端過載。

在交易時段開放期間隨時都有可能修改持倉。 不過,這種情況不會頻繁發(fā)生,而在每次逐筆報價時進行檢查則會顯著增加 EA 要執(zhí)行的操作。 在此我們可以利用事件。 根據(jù) MQL5 文檔,在交易服務器上完成一次交易操作時均會生成一個交易事件。 事件的結局會啟動 OnTrade 函數(shù)。 因此,該函數(shù)能夠啟動持倉和限價止盈之間的匹配檢查。 這樣我們就無需在每次逐筆報價時檢查匹配,同時也不會錯過任何變化。

接下來是標識問題。 初看,一切都很簡單。 赫茲股票量化應該簡單地檢查限價訂單和持倉。 然而,我們希望構建一套適用于不同帳戶類型和不同策略的通用算法。 另請注意,可以在策略中使用限價訂單。 因此,我們應該部署限價止盈。 我提議用注釋來標識它們。 由于我們的限價訂單用于取代止盈,我們將在訂單注釋的開頭添加 "TP" 來標識它們。 接下來,我們將添加一個階段編號,以防多階段持倉被誤操作平倉。 這對于凈持結算系統(tǒng)來說已經(jīng)足夠了,但是我們不要忘記對沖賬戶,它能夠在同一賬戶里開立多筆同品種的倉位。 因此,我們應該在限價止盈注釋中添加相應的倉位 ID。

3. 創(chuàng)建限價止盈類

赫茲股票量化總結一下上述內容。 我們類其功能可以分為兩個邏輯過程:

  1. 更改發(fā)送至服務器的交易請求。

  2. 監(jiān)控和調整持倉,并下達限價掛單。

為了便于使用,我們將算法設計為 CLimitTakeProfit 類,其中的所有函數(shù)聲明為靜態(tài)。 這樣我們就可以直接使用類方法,而無需在程序代碼中聲明其實例。 class CLimitTakeProfit : public CObject ? { private: ? ?static CSymbolInfo ? ? ? c_Symbol; ? ?static CArrayLong ? ? ? ?i_TakeProfit; //固定止盈 static CArrayDouble ? ? ?d_TakeProfit; //按盈利百分比平倉 public: ? ? ? ? ? ? ? ? ? ? ?CLimitTakeProfit(); ? ? ? ? ? ? ? ? ? ? ~CLimitTakeProfit(); //--- static void ? ? ? Magic(int value) ?{ ?i_Magic=value; } ? ?static int ? ? ? ?Magic(void) ? ? ? { ?return i_Magic;} //--- static void ? ? ? OnlyOneSymbol(bool value) ?{ ?b_OnlyOneSymbol=value; ?} ? ?static bool ? ? ? OnlyOneSymbol(void) ? ? ? ?{ ?return b_OnlyOneSymbol; } //--- static bool OrderSend(const MqlTradeRequest &request, MqlTradeResult &result); ? ?static bool OnTrade(void); ? ?static bool ? ? ? AddTakeProfit(uint point, double percent); ? ?static bool ? ? ? DeleteTakeProfit(uint point); ? ? protected: ? ?static int ? ? ? ?i_Magic; ? ? ? ? ?//用于控制的魔幻數(shù)字 static bool ? ? ? b_OnlyOneSymbol; ?//僅針對一個品種的控制 //--- static bool ? ? ? SetTakeProfits(ulong position_ticket, double new_tp=0); ? ?static bool ? ? ? SetTakeProfits(string symbol, double new_tp=0); ? ?static bool ? ? ? CheckLimitOrder(MqlTradeRequest &request); ? ?static void ? ? ? CheckLimitOrder(void); ? ?static bool ? ? ? CheckOrderInHistory(ulong position_id, string comment, ENUM_ORDER_TYPE type, double &volume, ulong call_position=0); ? ?static double ? ? GetLimitOrderPriceByComment(string comment); ? }; Magic, OnlyOneSymbol, AddTakeProfit 和 DeleteTakeProfit 方法是用于配置類操作的方法。 Magic — 用于跟蹤持倉的魔幻數(shù)字(對沖賬戶)。 如為 -1, 該類適用于所有倉位。 OnlyOneSymbol 指示該類僅針對 EA 啟動時的圖表品種工作。 AddTakeProfit 和 DeteleTakeProfit 方法用于添加和刪除固定止盈價位,并指示要平倉的交易量占初始倉量的百分比。 用戶可以根據(jù)需要應用這些方法,但它們都是可選的。 默認情況下,該方法適用于未設置固定止盈的所有魔幻數(shù)字和品種。 僅設置限價訂單來替代指定持倉的止盈。

3.1. 修改發(fā)送交易訂單

OrderSend 方法會監(jiān)視 EA 發(fā)送的訂單。 方法調用的名稱和形式類似于向 MQL5 發(fā)送訂單的標準函數(shù)。 用我們的方法替換標準函數(shù),簡化了將算法嵌入到先前編寫的 EA 代碼中。

赫茲股票量化已經(jīng)闡述了用掛單替換止盈的問題。 為此,我們只能在此模塊中替換市場中訂單的止盈。 但請記住,由服務器接受的訂單并不一定意味著它將被執(zhí)行。 此外,在發(fā)送訂單后,我們會收到訂單編號,但不會收到倉位 ID。 所以,我們將在監(jiān)控模塊中取代止盈。 在此,我們只跟蹤先前已設定止盈變化的時刻。

在方法代碼的開頭,檢查所發(fā)送請求是否對應于算法操作的過濾器設置。 另外,我們應該檢查交易的類型。 它應該對應于持倉的止損價位修改請求。 另外,不要忘記檢查請求中是否存在止盈。 如果請求難以滿足其中至少一個需求,則會立即將其發(fā)送到服務器。

檢查需求后,請求將傳遞給 SetTakeProfit 方法,在該方法中會放置限價訂單。 請注意,該類具有兩種使用持倉單號和品種的方法。 如果請求不包含持倉單號,則第二個更適用于凈持帳戶。 如果方法成功,則將請求中的止盈字段設置為零。

由于該請求可能會改變止盈和止損,因此請檢查該持倉中的止損和止盈是否恰當。 如有必要,則向服務器發(fā)送請求并退出該函數(shù)。 完整的方法代碼顯示如下。

bool CLimitTakeProfit::OrderSend(MqlTradeRequest &request,MqlTradeResult &result) ?{ ? if((b_OnlyOneSymbol && request.symbol!=_Symbol) || ? ? ?(i_Magic>=0 && request.magic!=i_Magic) || !(request.action==TRADE_ACTION_SLTP && request.tp>0)) ? ? ?return(::OrderSend(request,result)); //--- ? if(((request.position>0 && SetTakeProfits(request.position,request.tp)) || ? ? ? (request.position<=0 && SetTakeProfits(request.symbol,request.tp))) && request.tp>0) ? ? ?request.tp=0; ? if((request.position>0 && PositionSelectByTicket(request.position)) || ? ? ?(request.position<=0 && PositionSelect(request.symbol))) ? ? { ? ? ?if(PositionGetDouble(POSITION_SL)!=request.sl || PositionGetDouble(POSITION_TP)!=request.tp) ? ? ? ? return(::OrderSend(request,result)); ? ? } //--- ? return true; ?}

現(xiàn)在,我們詳細分析一下 SetTakeProfit 方法。 在方法的開頭,檢查指定的持倉是否存在,以及我們是否要處理該持倉品種。 接下來,更新持倉品種的數(shù)據(jù)。 之后,計算限價訂單的最接近許可價格。 如果出現(xiàn)任何錯誤,則使用 "false" 結果退出方法。

bool CLimitTakeProfit::SetTakeProfits(ulong position_ticket, double new_tp=0) ?{ ? if(!PositionSelectByTicket(position_ticket) || (b_OnlyOneSymbol && PositionGetString(POSITION_SYMBOL)!=_Symbol)) ? ? ?return false; ? if(!c_Symbol.Name(PositionGetString(POSITION_SYMBOL)) || !c_Symbol.Select() || !c_Symbol.Refresh() || !c_Symbol.RefreshRates()) ? ? ?return false; //--- ? double min_sell_limit=c_Symbol.NormalizePrice(c_Symbol.Ask()+c_Symbol.StopsLevel()*c_Symbol.Point()); ? double max_buy_limit=c_Symbol.NormalizePrice(c_Symbol.Bid()-c_Symbol.StopsLevel()*c_Symbol.Point());

之后,準備結構模板以便發(fā)送下達限價掛單的交易請求。 計算該持倉應設置或指定的止盈價位,所設的固定止盈不應超過計算出的距離。

? MqlTradeRequest tp_request={0}; ? MqlTradeResult tp_result={0}; ? tp_request.action = ?TRADE_ACTION_PENDING; ? tp_request.magic ?= ?PositionGetInteger(POSITION_MAGIC); ? tp_request.type_filling = ?ORDER_FILLING_RETURN; ? tp_request.position=position_ticket; ? tp_request.symbol=c_Symbol.Name(); ? int total=i_TakeProfit.Total(); ? double tp_price=(new_tp>0 ? new_tp : PositionGetDouble(POSITION_TP)); ? if(tp_price<=0) ? ? ?tp_price=GetLimitOrderPriceByComment("TPP_"+IntegerToString(position_ticket)); ? double open_price=PositionGetDouble(POSITION_PRICE_OPEN); ? int tp_int=(tp_price>0 ? (int)NormalizeDouble(MathAbs(open_price-tp_price)/c_Symbol.Point(),0) : INT_MAX); ? double position_volume=PositionGetDouble(POSITION_VOLUME); ? double closed=0; ? double closed_perc=0; ? double fix_closed_per=0;

接下來,安排循環(huán)檢查和固定止盈。 首先,設置訂單注釋(編碼原理如上所述)。 然后確保在持倉或請求中指定的止盈不超過固定值。 如果超過,則轉到下一個止盈。 此外,請確保先前設置的限價訂單的交易量與持倉量不會溢出。 如果限價訂單與持倉量溢出,則退出循環(huán)。

? for(int i=0;i<total;i++) ? ? { ? ? ?tp_request.comment="TP"+IntegerToString(i)+"_"+IntegerToString(position_ticket); ? ? ?if(i_TakeProfit.At(i)<tp_int && d_TakeProfit.At(i)>0) ? ? ? ?{ ? ? ? ? if(closed>=position_volume || fix_closed_perc>=100) ? ? ? ? ? ?break;

下一步是填寫交易請求結構中缺失的元素。 為此,計算新限價訂單的交易量并指定訂單類型和開倉價。

//--- ? ? ? ? double lot=position_volume*MathMin(d_TakeProfit.At(i),100-closed)/(100-fix_closed_perc); ? ? ? ? lot=MathMin(position_volume-closed,lot); ? ? ? ? lot=c_Symbol.LotsMin()+MathMax(0,NormalizeDouble((lot-c_Symbol.LotsMin())/c_Symbol.LotsStep(),0)*c_Symbol.LotsStep()); ? ? ? ? lot=NormalizeDouble(lot,2); ? ? ? ? tp_request.volume=lot; ? ? ? ? switch((ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE)) ? ? ? ? ? { ? ? ? ? ? ?case POSITION_TYPE_BUY: ? ? ? ? ? ? ?tp_request.type=ORDER_TYPE_SELL_LIMIT; ? ? ? ? ? ? ?tp_request.price=c_Symbol.NormalizePrice(open_price+i_TakeProfit.At(i)*c_Symbol.Point()); ? ? ? ? ? ? ?break; ? ? ? ? ? ?case POSITION_TYPE_SELL: ? ? ? ? ? ? ?tp_request.type=ORDER_TYPE_BUY_STOP; ? ? ? ? ? ? ?tp_request.price=c_Symbol.NormalizePrice(open_price-i_TakeProfit.At(i)*c_Symbol.Point()); ? ? ? ? ? ? ?break; ? ? ? ? ? }

填寫交易請求后,檢查之前是否設置了具有相同參數(shù)的限價掛單。 為此,將已填充的請求結構傳遞給 CheckLimitOrder 方法(方法的算法將在下面研究)。 如果之前未設置訂單,則將設定的訂單交易量添加到該持倉的已設定交易量總和之中。 這對于確保持倉量和所放置的限價訂單交易量彼此對應是必要的。

? ? ? ? if(CheckLimitOrder(tp_request)) ? ? ? ? ? { ? ? ? ? ? ?if(tp_request.volume>=0) ? ? ? ? ? ? ?{ ? ? ? ? ? ? ? closed+=tp_request.volume; ? ? ? ? ? ? ? closed_perc=closed/position_volume*100; ? ? ? ? ? ? ?} ? ? ? ? ? ?else ? ? ? ? ? ? ?{ ? ? ? ? ? ? ? fix_closed_per-=tp_request.volume/(position_volume-tp_request.volume)*100; ? ? ? ? ? ? ?} ? ? ? ? ? ?continue; ? ? ? ? ? }

如果訂單尚未下達,則參考經(jīng)紀商關于當前價格的要求調整其價格,并向服務器發(fā)送請求。 如果請求成功發(fā)送,我們會將訂單的交易量添加到先前為該持倉設置的交易量之和。

? ? ? ? switch(tp_request.type) ? ? ? ? ? { ? ? ? ? ? ?case ORDER_TYPE_BUY_LIMIT: ? ? ? ? ? ? ?tp_request.price=MathMin(tp_request.price,max_buy_limit); ? ? ? ? ? ? ?break; ? ? ? ? ? ?case ?ORDER_TYPE_SELL_LIMIT: ? ? ? ? ? ? ?tp_request.price=MathMax(tp_request.price,min_sell_limit); ? ? ? ? ? ? ?break; ? ? ? ? ? } ? ? ? ? if(::OrderSend(tp_request,tp_result)) ? ? ? ? ? { ? ? ? ? ? ?closed+=tp_result.volume; ? ? ? ? ? ?closed_perc=closed/position_volume*100; ? ? ? ? ? ?ZeroMemory(tp_result); ? ? ? ? ? } ? ? ? ?} ? ? }

完成循環(huán)后,使用相同的算法放置限價訂單,來彌補指定價格的修訂請求(或持倉)中缺失的交易量。 如果交易量小于允許的最小交易量,則以 'false' 結果退出該函數(shù)。

? if(tp_price>0 && position_volume>closed) ? ? { ? ? ?tp_request.price=tp_price; ? ? ?tp_request.comment="TPP_"+IntegerToString(position_ticket); ? ? ?tp_request.volume=position_volume-closed; ? ? ?if(tp_request.volume<c_Symbol.LotsMin()) ? ? ? ? return false; ? ? ?tp_request.volume=c_Symbol.LotsMin()+MathMax(0,NormalizeDouble((tp_request.volume-c_Symbol.LotsMin())/c_Symbol.LotsStep(),0)*c_Symbol.LotsStep()); ? ? ?tp_request.volume=NormalizeDouble(tp_request.volume,2); //--- ? ? ?switch((ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE)) ? ? ? ?{ ? ? ? ? case POSITION_TYPE_BUY: ? ? ? ? ? tp_request.type=ORDER_TYPE_SELL_LIMIT; ? ? ? ? ? break; ? ? ? ? case POSITION_TYPE_SELL: ? ? ? ? ? tp_request.type=ORDER_TYPE_BUY_LIMIT; ? ? ? ? ? break; ? ? ? ?} ? ? ?if(CheckLimitOrder(tp_request) && tp_request.volume>=0) ? ? ? ?{ ? ? ? ? closed+=tp_request.volume; ? ? ? ? closed_perc=closed/position_volume*100; ? ? ? ?} ? ? ?else ? ? ? ?{ ? ? ? ? switch(tp_request.type) ? ? ? ? ? { ? ? ? ? ? ?case ORDER_TYPE_BUY_LIMIT: ? ? ? ? ? ? ?tp_request.price=MathMin(tp_request.price,max_buy_limit); ? ? ? ? ? ? ?break; ? ? ? ? ? ?case ?ORDER_TYPE_SELL_LIMIT: ? ? ? ? ? ? ?tp_request.price=MathMax(tp_request.price,min_sell_limit); ? ? ? ? ? ? ?break; ? ? ? ? ? } ? ? ? ? if(tp_request.volume<=0) ? ? ? ? ? { ? ? ? ? ? ?tp_request.volume=position_volume-closed; ? ? ? ? ? ?tp_request.volume=c_Symbol.LotsMin()+MathMax(0,NormalizeDouble((tp_request.volume-c_Symbol.LotsMin())/c_Symbol.LotsStep(),0)*c_Symbol.LotsStep()); ? ? ? ? ? ?tp_request.volume=NormalizeDouble(tp_request.volume,2); ? ? ? ? ? } ? ? ? ? if(::OrderSend(tp_request,tp_result)) ? ? ? ? ? { ? ? ? ? ? ?closed+=tp_result.volume; ? ? ? ? ? ?closed_perc=closed/position_volume*100; ? ? ? ? ? ?ZeroMemory(tp_result); ? ? ? ? ? } ? ? ? ?} ? ? } ? ? ?

在方法完成時,檢查放置的限價訂單交易量是否涵蓋持倉量。 如果是,將持倉的止盈設置為零并退出該函數(shù)。

? if(closed>=position_volume && PositionGetDouble(POSITION_TP)>0) ? ? { ? ? ?ZeroMemory(tp_request); ? ? ?ZeroMemory(tp_result); ? ? ?tp_request.action=TRADE_ACTION_SLTP; ? ? ?tp_request.position=position_ticket; ? ? ?tp_request.symbol=c_Symbol.Name(); ? ? ?tp_request.sl=PositionGetDouble(POSITION_SL); ? ? ?tp_request.tp=0; ? ? ?tp_request.magic=PositionGetInteger(POSITION_MAGIC); ? ? ?if(!OrderSend(tp_request,tp_result)) ? ? ? ? return false; ? ? } ? return true; ?}

赫茲股票量化來看看 CheckLimitOrder 方法的算法,以便全景完整。 在功能上,該方法檢查已準備完畢的交易請求是否存在先前已放置的限制訂單。 如果已設置訂單,則該方法返回 "true",且不會設置新訂單。

在方法開始時,判斷放置限價訂單的最接近的可能價位。 如果有必要修改先前所下訂單,我們將需要它們。

bool CLimitTakeProfit::CheckLimitOrder(MqlTradeRequest &request) ?{ ? double min_sell_limit=c_Symbol.NormalizePrice(c_Symbol.Ask()+c_Symbol.StopsLevel()*c_Symbol.Point()); ? double max_buy_limit=c_Symbol.NormalizePrice(c_Symbol.Bid()-c_Symbol.StopsLevel()*c_Symbol.Point());

下一步是安排循環(huán)來迭代所有持倉。 由其注釋來標識必要的訂單。

? for(int i=0;i<total;i++) ? ? { ? ? ?ulong ticket=OrderGetTicket((uint)i); ? ? ?if(ticket<=0) ? ? ? ? continue; ? ? ?if(OrderGetString(ORDER_COMMENT)!=request.comment) ? ? ? ? continue;

搜索包含必要注釋的訂單時,檢查其交易量和訂單類型。 如果其中任一個參數(shù)不匹配,則刪除現(xiàn)有的掛單,并以 'false' 結果退出該函數(shù)。 如果訂單刪除錯誤,現(xiàn)有訂單的交易量將顯示在請求的交易量字段中。

? ? ?if(OrderGetDouble(ORDER_VOLUME_INITIAL) != request.volume || OrderGetInteger(ORDER_TYPE)!=request.type) ? ? ? ?{ ? ? ? ? MqlTradeRequest del_request={0}; ? ? ? ? MqlTradeResult del_result={0}; ? ? ? ? del_request.action=TRADE_ACTION_REMOVE; ? ? ? ? del_request.order=ticket; ? ? ? ? if(::OrderSend(del_request,del_result)) ? ? ? ? ? ?return false; ? ? ? ? request.volume=OrderGetDouble(ORDER_VOLUME_INITIAL); ? ? ? ?}

在下一階段,檢查已檢測到的訂單的開倉價和參數(shù)中指定的價格。 如有必要,修改當前訂單并以 "true" 結果退出方法。

? ? ?if(MathAbs(OrderGetDouble(ORDER_PRICE_OPEN)-request.price)>=c_Symbol.Point()) ? ? ? ?{ ? ? ? ? MqlTradeRequest mod_request={0}; ? ? ? ? MqlTradeResult mod_result={0}; ? ? ? ? mod_request.action=TRADE_ACTION_MODIFY; ? ? ? ? mod_request.price=request.price; ? ? ? ? mod_request.magic=request.magic; ? ? ? ? mod_request.symbol=request.symbol; ? ? ? ? switch(request.type) ? ? ? ? ? { ? ? ? ? ? ?case ORDER_TYPE_BUY_LIMIT: ? ? ? ? ? ? ?if(mod_request.price>max_buy_limit) ? ? ? ? ? ? ? ? return true; ? ? ? ? ? ? ?break; ? ? ? ? ? ?case ORDER_TYPE_SELL_LIMIT: ? ? ? ? ? ? ?if(mod_request.price<min_sell_limit) ? ? ? ? ? ? ? ? return true; ? ? ? ? ? ? ?break; ? ? ? ? ? } ? ? ? ? bool mod=::OrderSend(mod_request,mod_result); ? ? ? ?} ? ? ?return true; ? ? }

不過,我們不應忘記,可能存在限價訂單已經(jīng)與交易量匹配的情況。 因此,如果在已放置掛單中未找到必要的訂單,則檢查當前倉位的訂單歷史記錄。 此功能在我們最后調用的 CheckOrderInHistory 方法中實現(xiàn)。

? if(!PositionSelectByTicket(request.position)) ? ? ?return true; //--- ? return CheckOrderInHistory(PositionGetInteger(POSITION_IDENTIFIER),request.comment, request.type, request.volume); ?}


根據(jù)帳戶類型,我們有兩個激活限價訂單的選項:


  1. 在某個位置直接激活(凈持賬戶)。

  2. 限價訂單反向開倉,倉位互平(對沖賬戶)。


在搜索這種可能性時,請注意此類訂單也許與此持倉無關,因此我們將執(zhí)行成交搜索,并從其一得到單號。

bool CLimitTakeProfit::CheckOrderInHistory(ulong position_id, string comment, ENUM_ORDER_TYPE type, double &volume, ulong call_position=0) ?{ ? if(!HistorySelectByPosition(position_id)) ? ? ?return true; ? int total=HistoryDealsTotal(); ? bool hedging=(AccountInfoInteger(ACCOUNT_MARGIN_MODE)==ACCOUNT_MARGIN_MODE_RETAIL_HEDGING); //--- ? for(int i=0;i<total;i++) ? ? { ? ? ?ulong ticket=HistoryDealGetTicket((uint)i); ? ? ?ticket=HistoryDealGetInteger(ticket,DEAL_ORDER); ? ? ?if(!HistoryOrderSelect(ticket)) ? ? ? ? continue; ? ? ?if(ticket<=0) ? ? ? ? continue;

對于對沖賬戶,我們應首先檢查訂單是否與另一筆持倉相關。 如果檢測到來自其它持倉的訂單,則依據(jù)該持倉搜索具有必要注釋的訂單。 為此,執(zhí)行 CheckOrderInHistory 函數(shù)的遞歸調用。 為避免死循環(huán),請在調用方法之前檢查方法是否自此持倉調用。 如果檢測到訂單,則以 "true" 結果退出方法。 否則,重新加載持倉的歷史記錄并繼續(xù)下一筆成交。

? ? ?if(hedging && HistoryOrderGetInteger(ticket,ORDER_POSITION_ID)!=position_id && HistoryOrderGetInteger(ticket,ORDER_POSITION_ID)!=call_position) ? ? ? ?{ ? ? ? ? if(CheckOrderInHistory(HistoryOrderGetInteger(ticket,ORDER_POSITION_ID),comment,type,volume)) ? ? ? ? ? ?return true; ? ? ? ? if(!HistorySelectByPosition(position_id)) ? ? ? ? ? ?continue; ? ? ? ?}


股票量化交易軟件:使用限價訂單替代止盈且無需修改 EA 的原始代碼的評論 (共 條)

分享到微博請遵守國家法律
上杭县| 鄂伦春自治旗| 油尖旺区| 和田县| 东海县| 佛山市| 临夏县| 安塞县| 观塘区| 洪雅县| 明星| 乐至县| 沾益县| 丹阳市| 西林县| 铜梁县| 商水县| 高安市| 射洪县| 东丽区| 朝阳区| 白朗县| 子长县| 宿州市| 丘北县| 丰原市| 朔州市| 奇台县| 崇左市| 夏津县| 芷江| 台前县| 竹溪县| 醴陵市| 西和县| 成安县| 平遥县| 安吉县| 宁陵县| 元氏县| 井研县|