交易EA合集:四類策略源碼拆解與實(shí)戰(zhàn)回測(cè)指南)
簡介MT4自動(dòng)交易系統(tǒng)資源包面向外匯交易者、EA開發(fā)愛好者及初學(xué)量化策略的投資者匯總了多套自動(dòng)交易策略與配套學(xué)習(xí)材料覆蓋從策略邏輯理解、MQL4源碼修改到MT4平臺(tái)加載運(yùn)行的完整鏈路。壓縮包內(nèi)共151個(gè)文件主要包括53個(gè)mq4源碼文件與51個(gè)ex4編譯程序便于對(duì)照學(xué)習(xí)或直接掛載到圖表上運(yùn)行另外還提供了rar/zip打包的策略合集、doc文檔說明、tpl圖表模板、txt使用筆記等輔助理解規(guī)則細(xì)節(jié)與風(fēng)控思路。整體包體大小約16.99MB目前已有998人學(xué)習(xí)下載。內(nèi)容還包含海豚交易系統(tǒng)7.0交易規(guī)則、文字版對(duì)照錄音以及正確理解虧損、遵守紀(jì)律高于一切等交易理念文檔適合希望把自動(dòng)執(zhí)行與人工監(jiān)督結(jié)合的中級(jí)交易者按需選用也可作為編寫自研EA的參考范例。1. MT4自動(dòng)交易EA合集四個(gè)能直接編譯掛載的策略源碼入口MT4自動(dòng)交易里有個(gè)反直覺的現(xiàn)象回測(cè)曲線最漂亮的EA往往爆倉最快。尤其是網(wǎng)格馬丁類利潤曲線看著像穩(wěn)步爬坡實(shí)際是在給一次大回撤攢風(fēng)險(xiǎn)。這篇文章要拆解的這套資源是一份包含四個(gè)完整EA源碼的合集包涵蓋均線交叉、網(wǎng)格馬丁、通道突破、趨勢(shì)跟蹤這四類最常見的自動(dòng)交易策略。每個(gè)EA都是獨(dú)立的.mq4源碼帶止損止盈、魔術(shù)編號(hào)和倉位控制編譯后拖到圖表上就能跑。適合剛到MT4自動(dòng)交易門口、想找一個(gè)現(xiàn)成EA跑通全流程的新手也適合想拿現(xiàn)成代碼改參數(shù)做二次開發(fā)的熟手。下面按我的拆包順序先看資源落地到家目錄的完整路徑再逐段拆核心邏輯然后講回測(cè)參數(shù)最后寫常見坑和改造思路。2. 目錄結(jié)構(gòu)與工作臺(tái)準(zhǔn)備從壓縮包到策略測(cè)試器的完整落地拿到源碼包先別急著雙擊第一步是搞清里面每個(gè)文件是干什么的。MT4對(duì)文件目錄有嚴(yán)格約定放錯(cuò)文件夾導(dǎo)航器里就找不到程序這一步卡住的人不少。2.1 資源包構(gòu)成.mq4源碼、.set參數(shù)與.ex4程序的各自分工資源解壓后通常是這樣的目錄結(jié)構(gòu)MT4_EA_Pack/ ├── MQL4/ │ └── Experts/ │ ├── MACrossEA.mq4 │ ├── GridMartinEA.mq4 │ ├── BreakoutEA.mq4 │ └── TrendFollowEA.mq4 ├── Presets/ │ ├── MACrossEA_Default.set │ ├── GridMartinEA_Conservative.set │ └── BreakoutEA_H4.set └── 說明文檔.txt這個(gè)結(jié)構(gòu)里.mq4是MQL4語言的源代碼用MetaEditor打開后按F7即可編譯。.ex4是編譯后的可執(zhí)行程序正常OBJ存在于MQL4/Experts目錄圖表導(dǎo)航器左側(cè)的“智能交易系統(tǒng)”列表就是掃描這個(gè)目錄顯示的。.set是參數(shù)預(yù)設(shè)文件回測(cè)時(shí)在策略測(cè)試器“參數(shù)”選項(xiàng)卡里一鍵加載也可以在掛載EA到圖表后右鍵加載。我一般拿到EA源碼的第一件事就是打開MetaEditor重新編譯一遍而不是直接用包里帶的.ex4。原因很簡單MT4版本更新頻繁舊編譯產(chǎn)物經(jīng)常出現(xiàn)“incompatible version”提示自己本地編譯保證了EA與當(dāng)前平臺(tái)版本匹配。編譯成功后底部信息窗口會(huì)顯示類似MACrossEA.mq4 MACrossEA.ex4: 0 errors, 0 warnings出現(xiàn)這個(gè)結(jié)果說明源碼至少在語法層面是健康的。如果報(bào)錯(cuò)進(jìn)到第5章的排查部分看。2.2 MetaEditor環(huán)境準(zhǔn)備數(shù)據(jù)目錄、編譯選項(xiàng)與常用快捷鍵把資源包放進(jìn)MT4的正確姿勢(shì)是打開數(shù)據(jù)目錄。在MT4主界面按CtrlR是打開策略測(cè)試器但打開數(shù)據(jù)目錄的入口在“文件”菜單里點(diǎn)擊“打開數(shù)據(jù)文件夾”會(huì)彈出一個(gè)資源管理器窗口里面能看到MQL4目錄、tester目錄、config目錄等。然后把壓縮包里的文件分別合并進(jìn)去.mq4文件放進(jìn)MQL4/Experts/.set文件沒有強(qiáng)制目錄放哪都行加載時(shí)手動(dòng)定位.txt文檔隨意放置不參與平臺(tái)運(yùn)行。復(fù)制文件時(shí)如果MT4正在運(yùn)行建議先關(guān)閉MT4再復(fù)制或者復(fù)制完成后在導(dǎo)航器窗口按F4刷新否則資源管理器不會(huì)自動(dòng)感知新文件。我踩過一次這個(gè)坑文件復(fù)制進(jìn)去了導(dǎo)航器里怎么找都找不到后來發(fā)現(xiàn)是MT4啟動(dòng)時(shí)緩存了目錄列表重啟才好。MetaEditor里常用的是F7編譯、F4切回MT4主界面。編譯輸出窗口在下方雙擊錯(cuò)誤行會(huì)直接跳到對(duì)應(yīng)代碼位置。寫EA時(shí)我習(xí)慣把#property strict放在第一行這行聲明讓編譯器做嚴(yán)格的類型檢查能提前暴露很多隱藏問題。掛載EA到圖表還有一個(gè)高頻翻車點(diǎn)自動(dòng)交易總開關(guān)。MT4工具欄上有兩個(gè)相關(guān)按鈕一個(gè)是“算法交易”總開關(guān)一個(gè)在“選項(xiàng)→智能交易系統(tǒng)”里勾選“允許算法交易”。圖表被加載EA后右上角會(huì)顯示一個(gè)笑臉圖標(biāo)灰色笑臉表示自動(dòng)交易被禁用黃色笑臉才是運(yùn)行中。很多新手把EA拖上圖表就不管了看到灰色的笑臉還以為EA壞了其實(shí)是總開關(guān)沒打開。3. 核心模塊拆解均線交叉EA的完整交易鏈路這個(gè)EA是整套資源里最適合逐行精讀的一個(gè)。邏輯不復(fù)雜但開倉、平倉、倉位管理、訂單隔離這些完整鏈路都在讀懂它另外三個(gè)EA只是換策略信號(hào)而已。3.1 初始化與主循環(huán)雙均線信號(hào)怎么進(jìn)入狀態(tài)機(jī)先看整體骨架然后是開倉信號(hào)的核心判斷#property strict input double LotSize 0.01; input int FastMAPeriod 5; input int SlowMAPeriod 20; input int SL_Pips 30; input int TP_Pips 60; input int MagicNumber 202401; datetime lastBarTime 0; int OnInit() { return INIT_SUCCEEDED; } void OnTick() { if(Time[0] lastBarTime) return; lastBarTime Time[0]; double fastNow iMA(_Symbol, PERIOD_CURRENT, FastMAPeriod, 0, MODE_SMA, PRICE_CLOSE, 0); double fastPrev iMA(_Symbol, PERIOD_CURRENT, FastMAPeriod, 0, MODE_SMA, PRICE_CLOSE, 1); double slowNow iMA(_Symbol, PERIOD_CURRENT, SlowMAPeriod, 0, MODE_SMA, PRICE_CLOSE, 0); double slowPrev iMA(_Symbol, PERIOD_CURRENT, SlowMAPeriod, 0, MODE_SMA, PRICE_CLOSE, 1); if(fastPrev slowPrev fastNow slowNow) OpenOrder(OP_BUY); else if(fastPrev slowPrev fastNow slowNow) OpenOrder(OP_SELL); }Time[0]是當(dāng)前正在形成的K線開盤時(shí)間戳lastBarTime用來記錄上一次處理過的K線時(shí)間。這段代碼的核心作用是把策略從“每個(gè)tick都判斷”降頻成“每根新K線判斷一次”。這樣做最直接的好處是避免同一根K線內(nèi)反復(fù)觸發(fā)同一個(gè)信號(hào)導(dǎo)致在同一個(gè)價(jià)位附近開出好幾筆方向相同的單子。iMA這里取了四條數(shù)據(jù)快線當(dāng)前值和前一根K線的值、慢線當(dāng)前值和前一根K線的值。金叉的定義就是快線從慢線下方跑到上方也就是fastPrev slowPrev fastNow slowNow死叉反過來。PERIOD_CURRENT表示跟隨當(dāng)前圖表周期掛到H1圖上就按H1計(jì)算掛到M15就按M15這個(gè)設(shè)計(jì)能讓同一個(gè)EA在不同周期上復(fù)用。3.2 開倉函數(shù)手?jǐn)?shù)換算、止損止盈與魔術(shù)編號(hào)隔離信號(hào)觸發(fā)后進(jìn)入開倉函數(shù)這個(gè)函數(shù)是每次寫EA都會(huì)用到的模板void OpenOrder(int cmdType) { int count CountMyTrades(); if(count 0) return; double point _Point; if(_Digits 3 || _Digits 5) point _Point * 10; double price (cmdType OP_BUY) ? Ask : Bid; double sl 0, tp 0; if(SL_Pips 0) sl (cmdType OP_BUY) ? price - SL_Pips * point : price SL_Pips * point; if(TP_Pips 0) tp (cmdType OP_BUY) ? price TP_Pips * point : price - TP_Pips * point; int ticket OrderSend(_Symbol, cmdType, LotSize, price, 3, sl, tp, MA Cross, MagicNumber, 0, clrGreen); if(ticket 0) Print(開倉失敗錯(cuò)誤碼 IntegerToString(GetLastError())); else PrintFormat(開倉成功ticket%d價(jià)格%f, ticket, price); }CountMyTrades這個(gè)函數(shù)的寫法很典型它倒序遍歷整個(gè)訂單列表只統(tǒng)計(jì)當(dāng)前圖表、當(dāng)前魔術(shù)編號(hào)下的訂單int CountMyTrades() { int cnt 0; for(int i OrdersTotal() - 1; i 0; i--) { if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) { if(OrderSymbol() _Symbol OrderMagicNumber() MagicNumber) cnt; } } return cnt; }魔術(shù)編號(hào)是EA自我保護(hù)的關(guān)鍵。一個(gè)賬戶里可以有多個(gè)EA在跑甚至同圖表掛兩個(gè)策略如果把OrderSelect選中后直接對(duì)訂單操作很可能會(huì)動(dòng)到別的EA甚至手工單。通過OrderMagicNumber()和OrderSymbol()雙重過濾保證這個(gè)EA只管自己名下的單子。我在寫多策略組合時(shí)會(huì)給每個(gè)EA分配一個(gè)獨(dú)立的MagicNumber區(qū)間這樣后續(xù)做統(tǒng)計(jì)和風(fēng)控時(shí)一眼就能識(shí)別訂單歸屬。止損止盈這里有個(gè)單位換算問題_Point在5位報(bào)價(jià)下是0.00001而傳統(tǒng)意義上的1 pip在5位報(bào)價(jià)下是10點(diǎn)所以要用_Point * 10來做換算。如果參數(shù)里SL_Pips設(shè)成30實(shí)際價(jià)格距離就是30個(gè)pipette。不同平臺(tái)的點(diǎn)值定義不一樣這個(gè)換算邏輯要配合自己平臺(tái)做調(diào)整。3.3 平倉與移動(dòng)止損尾盤離場(chǎng)、浮盈保護(hù)開倉只是開始資金曲線好不好看更取決于平倉管理。這個(gè)EA的平倉函數(shù)做了兩件事移動(dòng)止損和尾盤清倉void ManagePosition() { for(int i OrdersTotal() - 1; i 0; i--) { if(!OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) continue; if(OrderMagicNumber() ! MagicNumber || OrderSymbol() ! _Symbol) continue; if(MoveSL_Pips 0) { double newSL 0; if(OrderType() OP_BUY) newSL Bid - MoveSL_Pips * point; else newSL Ask MoveSL_Pips * point; if((OrderType() OP_BUY newSL OrderStopLoss()) || (OrderType() OP_SELL newSL OrderStopLoss())) { OrderModify(OrderTicket(), OrderOpenPrice(), NormalizeDouble(newSL, _Digits), OrderTakeProfit(), 0, clrRed); } } if(CloseBeforeBarClose_Minutes 0) { datetime barClose Time[0] PeriodSeconds(); if(TimeCurrent() barClose - CloseBeforeBarClose_Minutes * 60) CloseOrder(OrderTicket()); } } }移動(dòng)止損的邏輯關(guān)鍵在于只往盈利方向推。newSL OrderStopLoss()買單調(diào)用來判斷新止損價(jià)是否高于當(dāng)前止損價(jià)只有浮盈推進(jìn)時(shí)才調(diào)用OrderModify否則頻繁修改止損既增加系統(tǒng)調(diào)用開銷也可能觸發(fā)平臺(tái)限制。OrderModify前必須用NormalizeDouble(newSL, _Digits)對(duì)齊精度否則個(gè)別平臺(tái)會(huì)返回“invalid stops”錯(cuò)誤。尾盤清倉是一種典型的日內(nèi)交易紀(jì)律參數(shù)CloseBeforeBarClose_Minutes設(shè)為30就是提前30分鐘把當(dāng)根K線的持倉全部平掉避免隔夜跳空和突發(fā)事件。這個(gè)邏輯對(duì)新手特別友好它強(qiáng)制策略在固定的時(shí)間段內(nèi)結(jié)束交易不會(huì)留下一堆隔夜單等第二天開盤被甩。3.4 點(diǎn)差保護(hù)與手工單隔離防止買在最高點(diǎn)EA還有一個(gè)容易被忽視的細(xì)節(jié)——點(diǎn)差過濾。在數(shù)據(jù)公布時(shí)段點(diǎn)差會(huì)突然拉大此時(shí)信號(hào)可能剛好觸發(fā)如果照常開倉等于買在明顯不利的價(jià)位input int MaxSpreadPips 30; int spreadPips (int)((Ask - Bid) / point); if(spreadPips MaxSpreadPips) { Print(當(dāng)前點(diǎn)差過大跳過開倉); return; }Ask - Bid就是即時(shí)點(diǎn)差把它除以point得到以點(diǎn)表示的值。當(dāng)超過參數(shù)閾值時(shí)直接跳過本次開倉這就是把“不做這筆交易”當(dāng)成一種有效風(fēng)控手段。馬丁EA尤其需要這個(gè)保護(hù)它總在虧損后加倉如果加倉時(shí)點(diǎn)差過大等于在額外的成本上方繼續(xù)放大風(fēng)險(xiǎn)敞口。4. 參數(shù)回測(cè)與實(shí)盤掛載網(wǎng)格EA與突破EA的驗(yàn)證流程均線交叉EA看懂后剩下三個(gè)EA的核心邏輯快速過一遍重點(diǎn)講回測(cè)怎么做才可信。4.1 網(wǎng)格馬丁EA加倉間距、倍數(shù)與熔斷參數(shù)網(wǎng)格馬丁EA的策略思路是價(jià)格每下跌一檔買入一單每上漲一檔賣出一單持倉數(shù)量越多單筆手?jǐn)?shù)越大整體浮虧靠最后一批單子回本。核心加倉邏輯如下input double StartLot 0.01; input double LotMultiplier 1.5; input int GridStepPips 50; input int MaxTrades 6; input int MaxDrawdownPercent 30; void OnTick() { if(nextBuyPrice 0) { nextBuyPrice Ask - GridStepPips * point; nextSellPrice Bid GridStepPips * point; } if(Bid nextBuyPrice) { int cnt CountGridTrades(); if(cnt MaxTrades) { double lot NormalizeDouble(StartLot * MathPow(LotMultiplier, cnt), 2); OrderSend(_Symbol, OP_BUY, lot, Ask, 3, 0, 0, Grid, MagicNumber, 0, clrBlue); nextBuyPrice Ask - GridStepPips * point; } } if(Ask nextSellPrice) { int cnt CountGridTrades(); if(cnt MaxTrades) { double lot NormalizeDouble(StartLot * MathPow(LotMultiplier, cnt), 2); OrderSend(_Symbol, OP_SELL, lot, Bid, 3, 0, 0, Grid, MagicNumber, 0, clrRed); nextSellPrice Bid GridStepPips * point; } } }這里MathPow(LotMultiplier, cnt)計(jì)算加倉后的手?jǐn)?shù)第一單0.01第二單0.015第三單0.0225呈幾何級(jí)數(shù)增長。MaxTrades是總單數(shù)上限這是網(wǎng)格馬丁EA最關(guān)鍵的熔斷參數(shù)沒有它遇到單邊趨勢(shì)會(huì)一直加倉到爆倉。浮虧熔斷是網(wǎng)格馬丁的“后悔藥”當(dāng)全部網(wǎng)格單的總浮虧超過賬戶余額一定比例時(shí)強(qiáng)制清倉double globalProfit 0; for(int i OrdersTotal() - 1; i 0; i--) { if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) { if(OrderSymbol() _Symbol OrderMagicNumber() MagicNumber) globalProfit OrderProfit() OrderSwap(); } } if(globalProfit 0) { double lossPercent MathAbs(globalProfit) / AccountBalance() * 100; if(lossPercent MaxDrawdownPercent) { CloseAllGridOrders(); Print(觸發(fā)熔斷全部網(wǎng)格單已清倉); } }我在跑這個(gè)EA的回測(cè)時(shí)會(huì)把GridStepPips分別設(shè)成30、50、80把MaxTrades設(shè)成4、6、8交叉對(duì)比。很多人只看總利潤曲線卻忽略了一個(gè)致命指標(biāo)——最大回撤。網(wǎng)格馬丁EA的利潤和回撤幾乎成正比參數(shù)越激進(jìn)回測(cè)曲線越好看實(shí)盤爆倉風(fēng)險(xiǎn)越高。這個(gè)EA最好配合單一品種不要跨品種同時(shí)跑多個(gè)網(wǎng)格否則賬戶總倉位會(huì)瞬間失控。4.2 突破EA通道識(shí)別與訂單執(zhí)行突破EA的策略邏輯是統(tǒng)計(jì)過去N根K線的最高價(jià)和最低價(jià)形成一個(gè)箱體通道價(jià)格向上突破箱體上沿就做多向下跌破箱體下沿就做空。代碼比網(wǎng)格EA簡潔input int ChannelPeriod 24; input int BreakoutPips 10; input int SL_Pips 40; input int TP_Pips 80; double upLevel iHigh(_Symbol, PERIOD_H1, iHighest(_Symbol, PERIOD_H1, MODE_HIGH, ChannelPeriod, 1)); double dnLevel iLow(_Symbol, PERIOD_H1, iLowest(_Symbol, PERIOD_H1, MODE_LOW, ChannelPeriod, 1)); if(Bid upLevel BreakoutPips * point) OrderSend(_Symbol, OP_BUY, LotSize, Ask, 3, Ask - SL_Pips * point, Ask TP_Pips * point, Break, MagicNumber, 0, clrGreen); if(Ask dnLevel - BreakoutPips * point) OrderSend(_Symbol, OP_SELL, LotSize, Bid, 3, Bid SL_Pips * point, Bid - TP_Pips * point, Break, MagicNumber, 0, clrRed);iHighest返回過去24根K線中最高價(jià)的位置索引把這個(gè)索引再傳給iHigh取出具體價(jià)格值。BreakoutPips是過濾假突破的偏移量價(jià)格必須突破通道上沿并超過10點(diǎn)才觸發(fā)開倉。這樣做的目的是減少在通道邊緣反復(fù)震蕩時(shí)被反復(fù)打臉的次數(shù)。突破EA的回測(cè)參數(shù)重點(diǎn)在ChannelPeriod。周期太小通道窄觸發(fā)頻繁手續(xù)費(fèi)和止損成本會(huì)吃掉利潤周期太大通道寬信號(hào)少一年可能就幾筆交易。我一般用H1配合24周期做基準(zhǔn)再用48和72周期做對(duì)比觀察交易次數(shù)和凈利潤之間的平衡點(diǎn)。4.3 策略測(cè)試器跑出可信結(jié)果的參數(shù)模板回測(cè)不是簡單點(diǎn)“開始”就完事參數(shù)設(shè)置直接影響結(jié)論是否可信。我給這套資源跑回測(cè)時(shí)的固定模板如下配置項(xiàng)推薦設(shè)置原因交易品種與周期EURUSD H1主流品種流動(dòng)性好歷史數(shù)據(jù)完整回測(cè)區(qū)間至少2年覆蓋趨勢(shì)和震蕩行情建模方式每個(gè)tick基于真實(shí)tick最接近實(shí)盤成交路徑點(diǎn)差設(shè)置按當(dāng)前交易商默認(rèn)加點(diǎn)差忽略了點(diǎn)差會(huì)讓回測(cè)虛高參數(shù)加載加載對(duì)應(yīng)的.set文件保證和實(shí)盤掛載參數(shù)一致在策略測(cè)試器里加載.set文件的方式是選好EA后右側(cè)“參數(shù)”選項(xiàng)卡底部有一個(gè)“加載”按鈕點(diǎn)擊后定位到Presets目錄即可。加載后參數(shù)表會(huì)變成預(yù)設(shè)值再點(diǎn)“開始”跑回測(cè)。跑完主要看四個(gè)指標(biāo)凈利潤、最大回撤、盈利因子、總交易筆數(shù)。我特別留意總交易筆數(shù)如果一年只有不到20筆樣本量太小統(tǒng)計(jì)意義有限如果筆數(shù)很大但盈利因子只略高于1說明策略靠堆交易次數(shù)賺小錢手續(xù)費(fèi)一上調(diào)可能就轉(zhuǎn)為虧損。回測(cè)報(bào)告只能幫你排除明顯不合理的策略不能用來斷言未來收益這一點(diǎn)一定記牢。5. 常見問題排查編譯報(bào)錯(cuò)、回測(cè)失真與訂單不成交的實(shí)例記錄這套資源掛載過程中有幾個(gè)高頻問題我按實(shí)測(cè)踩坑記錄的形式整理出來每一條都按現(xiàn)象、原因、解決三步寫清楚。5.1 編譯不過歷史函數(shù)與新版MQL4的兼容差異現(xiàn)象把.mq4文件拖進(jìn)MetaEditor按F7下方錯(cuò)誤窗口彈出一片紅色最常見的報(bào)錯(cuò)是OrderSend - wrong parameters count和iMA - parameter conversion not allowed。原因新版MQL4編譯器默認(rèn)開啟嚴(yán)格模式要求函數(shù)參數(shù)數(shù)量和類型必須完全匹配。早期寫的EA代碼沒有#property strict聲明依賴編譯器自動(dòng)轉(zhuǎn)換類型在新版本下全部暴露成了錯(cuò)誤。另外Print里直接用拼接數(shù)字和字符串在新版里也被禁止必須用類型轉(zhuǎn)換函數(shù)。解決在源碼第一行加上#property strict。然后逐個(gè)錯(cuò)誤行修正整數(shù)參數(shù)用(int)顯式強(qiáng)轉(zhuǎn)打印字符串用IntegerToString(GetLastError())替換直接拼接。這類報(bào)錯(cuò)不是程序邏輯問題純粹是語法規(guī)范和版本兼容一般幾分鐘能修完。5.2 回測(cè)失真tick模式、點(diǎn)差與歷史數(shù)據(jù)質(zhì)量現(xiàn)象同一個(gè)EA用“每根K線”模式回測(cè)年化收益翻倍換成“每個(gè)tick基于真實(shí)tick”后利潤縮水一半在某交易商平臺(tái)的歷史數(shù)據(jù)上回測(cè)很漂亮換一家交易商數(shù)據(jù)后曲線完全變形。原因每根K線模式下系統(tǒng)假設(shè)訂單只在K線收盤價(jià)成交忽略了K線運(yùn)行過程中最高價(jià)、最低價(jià)對(duì)止損止盈的觸發(fā)路徑。點(diǎn)差設(shè)置也是一樣默認(rèn)的0點(diǎn)差回測(cè)會(huì)把每次開倉成本節(jié)省下來累積起來就是一筆虛擬利潤。解決回測(cè)建模方式一律選“每個(gè)tick基于真實(shí)tick”點(diǎn)差按實(shí)盤默認(rèn)值加上去。如果平臺(tái)沒有該品種的詳細(xì)tick數(shù)據(jù)在歷史數(shù)據(jù)中心先下載完整數(shù)據(jù)再回測(cè)。跑實(shí)盤前還要用可視化回測(cè)模式播放一遍確認(rèn)訂單開平倉位置和信號(hào)標(biāo)注一致。5.3 訂單不成交止損止盈距離、掛單距離與算法交易開關(guān)現(xiàn)象EA日志里打印invalid stops或直接沒有報(bào)錯(cuò)但圖表右上角EA圖標(biāo)是灰色的單子始終不開。原因invalid stops通常是止損價(jià)距離現(xiàn)價(jià)太近不滿足交易商的最小止損距離要求灰色圖標(biāo)是自動(dòng)交易總開關(guān)沒打開還有一種情況是前一次OrderSend還沒有返回結(jié)果下一次OrderSend已經(jīng)觸發(fā)系統(tǒng)返回trade context busy。解決止損參數(shù)先按平臺(tái)規(guī)定的最小止損距離設(shè)置比如某平臺(tái)要求止損至少距現(xiàn)價(jià)20點(diǎn)那么SL_Pips低于20就會(huì)被拒單。掛載EA前確認(rèn)工具欄“算法交易”按鈕已點(diǎn)亮。代碼層面在OrderSend前加while(IsTradeContextBusy()) Sleep(50);做等待并在下單后加少量Sleep(100)給平臺(tái)時(shí)間完成訂單上下文切換。5.4 回測(cè)最佳參數(shù)實(shí)盤翻車參數(shù)過擬合的自查點(diǎn)現(xiàn)象用2019到2021年的數(shù)據(jù)優(yōu)化出一組參數(shù)實(shí)盤跑了三個(gè)月開始連續(xù)虧損而同一時(shí)間段的回測(cè)曲線依然漂亮。原因這是一類典型過擬合問題。EA的input參數(shù)越多組合空間越大優(yōu)化器越容易找到一條只在歷史數(shù)據(jù)上成立的參數(shù)組合。真實(shí)施加行情里價(jià)格路徑不會(huì)完全重復(fù)過去最賺錢的參數(shù)往往也是對(duì)未來最敏感的參數(shù)。解決優(yōu)化完參數(shù)后用樣本外數(shù)據(jù)做驗(yàn)證——假設(shè)用2019-2021優(yōu)化就保留2022-2023的數(shù)據(jù)不參與優(yōu)化直接拿優(yōu)化后的參數(shù)去跑這一段。如果兩段數(shù)據(jù)表現(xiàn)差距過大說明參數(shù)過擬合。排查時(shí)還看兩個(gè)點(diǎn)策略中的邏輯是否依賴特定品種的波動(dòng)特性以及交易筆數(shù)是否足夠支撐結(jié)論。我自己的經(jīng)驗(yàn)是把參數(shù)數(shù)量控制在6個(gè)以內(nèi)同時(shí)只優(yōu)化最核心的三四個(gè)能顯著降低過擬合概率。6. 二次開發(fā)把單品種EA改造成多品種輪詢的風(fēng)控管理器最后給一個(gè)具體的改造方向把單圖表EA改成一份代碼同時(shí)監(jiān)控多個(gè)品種用一個(gè)圖表管理整個(gè)賬戶的自動(dòng)交易。核心思路是抽離品種相關(guān)的部分。原代碼里大量使用_Symbol、PERIOD_CURRENT改造后全部換成參數(shù)傳入。我在OnInit里用StringSplit解析逗號(hào)分隔的品種列表再為每個(gè)品種分配獨(dú)立的MagicNumber段input string TradeSymbols EURUSD,GBPUSD,XAUUSD; input int BaseMagic 202410; input double MaxTotalLot 0.5; string Symbols[]; int Magics[]; int OnInit() { string parts[]; int n StringSplit(TradeSymbols, ,, parts); ArrayResize(Symbols, n); ArrayResize(Magics, n); for(int i 0; i n; i) { Symbols[i] parts[i]; Magics[i] BaseMagic i; } return INIT_SUCCEEDED; } void OnTick() { for(int i 0; i ArraySize(Symbols); i) { string sym Symbols[i]; if(TotalOpenLot() MaxTotalLot) continue; CheckSignal(sym, Magics[i]); } }CheckSignal就是原來均線交叉EA里的開倉判斷只是把_Symbol替換成了sym參數(shù)把MagicNumber替換成Magics[i]。TotalOpenLot統(tǒng)計(jì)賬戶所有訂單的總手?jǐn)?shù)超過閾值就跳過新開倉這是多品種版最需要的全局風(fēng)控原先每個(gè)EA只管自己多個(gè)EA同時(shí)開倉時(shí)賬戶總體倉位可能失控。改造后的驗(yàn)證流程我每次必走四步先用原來的單品種參數(shù)跑一遍回測(cè)作為基線記錄凈利潤和最大回撤然后跑多品種版本對(duì)比總手?jǐn)?shù)曲線是否超出預(yù)期接著用可視化模式觀察一遍訂單序列確認(rèn)多個(gè)品種之間的下單順序和風(fēng)控邏輯沒有互相干擾最后在小倉位模擬盤掛一周觀察真實(shí)點(diǎn)差下執(zhí)行是否正常。從那以后我每次改完EA都強(qiáng)制走一遍這四步缺一步都不上實(shí)盤這套流程幫我避掉過好幾回改造引入莫名其妙的虧損源。希望幫到你。本文還有配套的精品資源點(diǎn)擊獲取