如何使用MT5做股市期貨歷史回測的方法 - 页 2

 
ambercrystal #:

因为个人在2017年也设计过 mt4/mt5 借用 ea 架构来看盘 A股港股美股的设计,mt4 是走自己定义图表的方式,mt5 是和楼主一样用 mt5 custom symbol 的模式,只是改为 ea 自动联网行情数据导入,这样开市时才能自动刷新k线,只是产品是用来卖钱的,不好在这里多说。


但其实如果目的是要复盘 A股,是可以不用这么辛苦在 mt5 上搞 CustomSymbol 和 A股复盘。。。


只是在 MetaQuotes 这里的论坛说这个不知道是否会不合适,呵呵。。。有个看盘软件 TradingView 哪里有名国家的股票行情数据都有,也包含 A股,日线分钟线也还都很长,只是复盘的策略需要用他们的 pine script 来写,复盘 A股,用免费会员账号还是可以达成的,

如果策略不复杂,转写还是很快的。也写过几篇关于这些的博文,如果有兴趣可以百度 "sina boolapi"。


版主,如果有发言不合适的地方,请见谅,只是分享多一些方式,让有 A股复盘策略需求的交易朋友知道。

謝謝分享 當然可以復盤A股的工具很多

py或是c能力強的量化交易者大多可以製作自己使用的交易工具 並且可以做復盤及優化工作

我在這裡分享 就是單獨使用mql5提供的工具及可行的方法來做策略的復盤 

也希望你能分享一些你的經驗或是方法 造福所有參與的愛好者

 

用 python 复盘交易商品的线上平台,最早在美国出现一堆新创公司,例如 Quantopian,QuantConnect,大概就是喜欢用 Quant 开头,不过这样的服务很难找到盈利点,所以最有名的 Quantopian 已经在 2020 年关门了,其他的平台还在努力中,这些都可以复盘美国期货或美股,个人用过 QuantConnect 一阵子。


在互联网行业,就是美国有什么新概念,中国就快速复制什么,所以当时这些 Quant 辈的线上量化平台在美国出现不久,中国很快出现了聚宽这些新创公司,应该都是用 python,可以复盘 a 股这些。传统券商也有进来这块服务,不过广发好像进来不久又退出了,最近有一些讨论是国信证券的线上量化平台。


我上面回复提到的 TradingView 不是这类的线上平台,但是优点是这个平台有许多国家的股票数据,pine script 也不是很难,简单策略还是容易转写的。

 

之前提到過 可以用更便捷的方式來進行建立品種及歷史數據導入的工作 從這篇開始逐一介紹


我這裡介紹使用腳本的方式快速且詳細的建立方式 

首先 先準備好一份欲建立的清單 清單需要儲存成CSV檔 (可以使用**信軟件匯出自訂義 詳細方法須自行去測試)

SymbolCreat


將清單存檔在該帳號的File文件夾裡面 文件夾開啟方式如下

1/. 點擊左上方Fils\Open Date Folder

SymbolCreat1


2/. 點擊進入MQL5\Files

SymbolCreat2

SymbolCreat3


3/. 將清單檔放置在文件夾理

SymbolCreat4




使用腳本Stock Symbol Create 快速建立清單裡的所有品種

SymbolCreat5

腳本的輸入參數功能

1/. 品種清單 輸入建立好的品種清單 需添加副檔名 

2/. 建倉最小單量 每次下單的最小手數

3/. 建倉最大單量 每次下單的最大手數

4/. 建倉增加單位 下單時可以增加的數量 輸入1 則以 1 2 3....100可下單 詳細可以倒車看一下前面的介紹

5/. 每單交易數量 也就是合約數量 每一手下單的股數 外匯交易時合約數量是100000一手 標準黃金是100oz 一手 台股是1000股一手 陸股應該是100股一手 如果是交易零股那就可以設置成1

6/. 交易使用幣種 交易盈虧保證金使用到的幣種 如果是使用USD帳戶 就設置成USD 如果是AUD帳戶就設置成AUD 這關係到回測時的計算數據

7/. 分類名稱 因為鼓號可能很多 所以在腳本代碼裡面有設置群組功能 此欄位即在群組前面加入名稱 群組代碼如下

SymbolCreat6

如果覺得不需分類 可以將這段代碼By Pass 也可以根據自己的需求在這一段作修改


導入後腳本提示品重創件成功

SymbolCreat7


檢查品種列表是否創建成功 並檢查品種的明細是否正確 如果明細有誤可以重新加載腳本 腳本會重新刷新需要明細

明細需要注意的項目可以倒車回看前面介紹的部分

SymbolCreat8

我因為是繁體電腦 使用檢體的清單 所以會有亂碼發生 這錯誤可以忽略 在清單上使用繁體 或是切換成檢體的系統就可以排除此問題


腳本的代碼如下

//+------------------------------------------------------------------+
//|                                          Stock Symbol Create.mq5 |
//|                                                        Submarine |
//|                                      WeChart:ExpertAdvisorTrader |
//+------------------------------------------------------------------+
#property copyright "Submarine"
#property link      "WeChart:ExpertAdvisorTrader"
#property version   "1.00"
#property description "品種建立清單須為為CSV格式,需連同附檔名一起輸入"


#property script_show_inputs
//--- input parameters
input string            file_name        = "Sheet1.csv"; //品種清單
input int         MinOrder     = 1;                //建倉最小單量
input int         MaxOrder     = 100;           //建倉最大單量
input int         OrderStep    = 1;                //建倉增加單位
input int         ContractSize = 100;          //每單交易數量
input string      BaseCurrency = "USD";        //交易使用幣種
input string      GroupName    = "SZ";         //分類名稱
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
{
        //---
        string symb_name;
        string meigara;
        string group_name;
        string strValue;
        string result[5];
        string sep      = ",";
        ushort u_sep = StringGetCharacter(sep, 0);
        int      num, count = 0;
        int      read_handle;
        int      write_handle;
        long     number;
        bool     ret_value;
        bool     is_custom = true;

        read_handle  = FileOpen(file_name, FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_ANSI|FILE_TXT);
        write_handle = FileOpen("SymbolList.txt", FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_ANSI|FILE_TXT);
        
        if (read_handle != INVALID_HANDLE)
        {
           while (!FileIsEnding(read_handle))
                {
                   strValue = FileReadString(read_handle);
                        num = StringSplit(strValue, u_sep, result);
                        
                        if (num > 0 )
                        {
                           symb_name = result[0];                                       
                                StringTrimLeft(symb_name);
                                StringTrimRight(symb_name);
                                Comment("\r\n\r\nUpdate " + symb_name);
                                
                                meigara = result[1];                                            
                                StringTrimRight(meigara);
                                
                                if(GroupName!="")
                          {
                                number = StringToInteger(symb_name);
                                if (number > 999999)
                                        continue;
                                if (number < 100000)
                                        group_name = GroupName+"000000";
                                else
                                {
                                        number = (long)(MathFloor(number / 100000) * 100000);   
                                        group_name = GroupName+IntegerToString(number);
                                }
                          }
                                
                                if (!SymbolExist(symb_name, is_custom))
                                {
                                        ret_value = CustomSymbolCreate(symb_name, group_name, NULL);
                                        
                                        if (!ret_value)
                                        {
                                                Alert("Failed to create symbol for " + symb_name);
                                                continue;
                                        }
                                        else
                                        {
                                                count += 1;
                                                FileWriteString(write_handle, "Added: " + symb_name + " " + meigara + "\r\n");
                                                FileFlush(write_handle);
                                        }
                                }

                                if (SymbolInfoString(symb_name, SYMBOL_DESCRIPTION) != meigara)
                                        CustomSymbolSetString(symb_name, SYMBOL_DESCRIPTION, meigara);                  
                                
                                if (SymbolInfoString(symb_name, SYMBOL_CURRENCY_BASE) != BaseCurrency)
                                   CustomSymbolSetString(symb_name, SYMBOL_CURRENCY_BASE,BaseCurrency);
                           if (SymbolInfoString(symb_name, SYMBOL_CURRENCY_PROFIT) != BaseCurrency)
                                   CustomSymbolSetString(symb_name, SYMBOL_CURRENCY_MARGIN,BaseCurrency);
                           if (SymbolInfoString(symb_name, SYMBOL_CURRENCY_MARGIN) != BaseCurrency)
                                   CustomSymbolSetString(symb_name, SYMBOL_CURRENCY_PROFIT,BaseCurrency);
                           if (SymbolInfoDouble(symb_name, SYMBOL_MARGIN_INITIAL) != 0)
                                   CustomSymbolSetDouble(symb_name, SYMBOL_MARGIN_INITIAL,0);
                           if (SymbolInfoDouble(symb_name, SYMBOL_VOLUME_MIN) != MinOrder)
                                   CustomSymbolSetDouble(symb_name, SYMBOL_VOLUME_MIN,MinOrder);
                           if (SymbolInfoDouble(symb_name, SYMBOL_VOLUME_MAX) != MaxOrder)
                                   CustomSymbolSetDouble(symb_name, SYMBOL_VOLUME_MAX,MaxOrder);
                           if (SymbolInfoDouble(symb_name, SYMBOL_VOLUME_STEP) != OrderStep)
                                   CustomSymbolSetDouble(symb_name, SYMBOL_VOLUME_STEP,OrderStep);
                           if (SymbolInfoDouble(symb_name, SYMBOL_TRADE_CONTRACT_SIZE) != ContractSize)
                                   CustomSymbolSetDouble(symb_name, SYMBOL_TRADE_CONTRACT_SIZE,ContractSize);
                           if (SymbolInfoInteger(symb_name, SYMBOL_TRADE_CALC_MODE) != SYMBOL_CALC_MODE_EXCH_STOCKS_MOEX)
                                   CustomSymbolSetInteger(symb_name, SYMBOL_TRADE_CALC_MODE,SYMBOL_CALC_MODE_EXCH_STOCKS_MOEX);
                        }
                }
                
                FileClose(read_handle);
                FileClose(write_handle);
        }
        
        MessageBox((string)count + " symbols have been registered succesfully.", "完了", MB_OK);
        Comment("");
        //---
}
//+------------------------------------------------------------------+


腳本原始作者是第一篇介紹果的一位日本匠人 非常感謝他無私地分享代碼

我就是根據自己的需求修改了部分的功能 讓腳本能夠更健全的創建我需要的新品種

日後若有匯友有更好的想法 也請分享交流 讓腳本的功能能夠更加健全

後面我會找時間繼續介紹使用腳本的方式快速建立多品種的歷史資料

附加的文件:
 

快速創建新品種後 接下來就是快速導入歷史數據了

前面有提過可以從雅虎網站下載各國股市的日線圖 這裡提另一個例子 使用XX信的軟件可以下載到分鐘線的歷史資料

當然 歷史資料來源的方法很多 我這只能簡單的提一個例子


打開XX信軟件後 使用免費使用者登入 在自選下面創建要的清單

Import


接著 在系統底下選擇 數據倒出選項


Import1


選擇 Excel文件(因為腳本設計是使用CSV格式) 並點擊"高級導出"

Import2


1/. 點選要得時間段數據(本次選用分鐘線) XX信軟件設定分鐘顯只能下載100天資料 日線則沒有限制

2/.選擇好儲存的目錄

3/. 右下方點擊添加品種 此選項進入後可以找到一開始定義的自選品種 這裡就不多做詳細介紹


Import3


導出後就可以在設定的目錄裡找到檔案


Import5


將文件移動到帳戶所在的File夾裡面 並將檔名修改成品種的代號 用來對應該數據是導入到哪一個品種


Import6


打開原始文件的格式

Import9

整理後的格式

刪除表頭(文件末端還有要刪除的) 不必要的數據確認符合MQL要的格式 

Excel的數據整理需要幾個步驟 可以百度一下

Import10


將所有整理好的文件使用腳本一次性導入MQL

導入的方法有兩種

1/. 使用個別檔案 輸入整理好的檔名 不加附檔名 範例為600519.csv

2/. 使用清單 一次性將所有整理好的數據檔全部導入 同樣不加附檔名 範例為 自选股20210813.txt

Import11

下述文字清單的內容 記錄需要倒進的所有股號檔案


Import12


導入完成 腳本提示已完成一個或是多個數據的導入

Import13

然後就可以在報價表上調出完成導入的數據了

Import14


使用系統自帶的EA做簡單的測試

跟之前不一樣的是 因為導入是分鐘線 所以用不同的時間框做回測可以得到校準確的結果

Import15

跟之前的測試一樣 品質一樣顯示不好 但畢竟已經是分鐘級別的回測了 效果肯定比日線級別要準確

Import16


這次使用的腳本 是同一位日本匠人提供 我在稍做修改完成 該腳本可以讓我們快速地完成數據導入的工作 是非常好用的工具

工作至此 已經完全介紹利用MQL做創建品種及數據倒入的工作了 Excel的修改工作動作有點繁瑣 所以我就不在此多做介紹 有疑問的可以私下問我

或許我哪天有時間會在這篇終結的時候另做介紹

附加的文件:
 

這篇工作介紹進行到最後階段 就是讓日常的數據維護 

很遺憾的是 我並沒有想出一個通用的方法 可能只能用導入歷史數據的方法 每天刷新一下最新的歷史數據

另外的方法就是讀取網頁即時報價的數據 經過處理 再導入到歷史數據 但是這樣會高頻綠的刷屏 估計網站很快就會終止對你的數據服務


這裡我單獨提供一個台股自動更新的流程 供各位參考 但是使用的代碼就不提供了

首先使用XXX靈台股交易軟件 該軟件需要在對應銀行開立交易帳戶 並不提供免費使用

Take

該軟件有一非常好的功能 提供數據匯出到Excel的功能

可讀取的數據很多 經過測試思考後 我只取用成交價當作市價 總交易量 以及時間

Take1

將匯出的Excel檔案經過修改 做成我要的功能

改過的Excel作用是 計算分鐘的 開 高 低 收 四個價格 以及計算分鐘的成交量 並且將整個表計算後的數值每分鐘轉存成txt檔案

Take2

檔案夾可以看到將Excel轉存成txt檔案

我們開啟Excel在運行時 檔案是在記憶體運行 並不會落入硬盤 所以直接讀取時只會出現一堆Excel的代碼 而不是我們看到的計算數據

這是我為何要轉存成txt檔的原因

Take3

確定txt已經是我要的數據格式

使用編輯好的程序 讀取轉存的txt檔 並將數據寫入歷史資料庫中

Take4

調出報價表核對看看是否跟原始的K線圖是否合乎

Take6


整個數據的轉換過程

trans

1/. XXX靈交易軟件匯出即時價格至Excel

2/.Excel統計計算出MQL要的數據並轉存成txt檔案

3/.MQL讀取txt數據並寫入歷史數據


我使用的不是最優的方法 不過確定的是 即使不是專業的程序員也可以按照步驟逐一的完成

我提供的方法還是有缺陷存在 在寫入跟統計數據的時間上會有5秒的空白 但如果是用在小時線或是日線級別的交易 其實可以忽略不計

 在無法對接即時的數據庫 這應該也算是比較好的方法吧


這篇前前後後大概花了我兩個月的時間去測試及驗證 最後大概又用了兩三週的時間來寫這篇論壇

就如本篇開頭說的 分享經驗是我的一個目的 記錄整個過程是另一個目的 完成好的工作過兩個月後要再重做一次 估計我都忘光光了

在最後希望我的經驗能夠幫助到需要的人 也希望各位匯友能不吝賜教 提供更好的方法 分享更多的經驗 

 
非常棒!能用股票做回測已經很不錯了,希望將來能把程式套在股票上使用
 
非常有帮助,感谢分享
 

楼主您好,我在数据导入的时候发现超过120kb的文件数据不能导入,要想导入一年的一分钟数据,文件大小大约2m左右,就必须先拆分成若干小文件,然后再一个一个导入很是麻烦,不知道您那里遇到这种情况没,想找个解决的办法.

系统是windows10 简体

mt5版本

version:5.00 build 3280

 
yijiangxue #:

楼主您好,我在数据导入的时候发现超过120kb的文件数据不能导入,要想导入一年的一分钟数据,文件大小大约2m左右,就必须先拆分成若干小文件,然后再一个一个导入很是麻烦,不知道您那里遇到这种情况没,想找个解决的办法.

系统是windows10 简体

mt5版本

version:5.00 build 3280

我猜想 可能是你要導入的數據格式有問題 是不是有檢查過所有的數據都符合要求呢

 

導入數據的格式 在CSV裡面 要全部為文本格式 

導入前用筆記本檢查一下 是不是合乎導入的需求

原因: