pairs_trading/tool.mqh
super.admin 7aec422ada convert
2025-05-30 16:15:29 +02:00

480 lines
29 KiB
MQL5

#define TOSTR(A) #A+" = "+(string)A+" "
//+------------------------------------------------------------------+
//| ローソク足が確定したティックならtrue
//+------------------------------------------------------------------+
bool IsNewBar(ENUM_TIMEFRAMES tf = PERIOD_CURRENT)
{
static datetime time = 0;
static long msc = 0;
//--- ティック情報の取得
MqlTick tick;
SymbolInfoTick(_Symbol, tick);
if(iTime(_Symbol, tf, 0) == time && msc != tick.time_msc)
return false;
time = iTime(_Symbol, tf, 0);
msc = tick.time_msc;
return true;
}
//+------------------------------------------------------------------+
//| ティックがn回目ならtrue
//+------------------------------------------------------------------+
bool IsSpecifiedTick(const int n = 100)
{
static int tick_count = 0;
if(tick_count < n){
tick_count++;
return false;
}
tick_count = 0;
return true;
}
//+------------------------------------------------------------------+
//| 対数差収益率
//+------------------------------------------------------------------+
double iR(string sym, ENUM_TIMEFRAMES tf, int i)
{
double c0 = iClose(sym,tf,i);
double c1 = iClose(sym,tf,i+1);
return(log(c0) - log(c1));
}
//+------------------------------------------------------------------+
//| 上昇したティックであればtrue
//+------------------------------------------------------------------+
bool IsRisedTick()
{
static double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
bool ret = false;
if(SymbolInfoDouble(_Symbol, SYMBOL_BID) > bid)
ret = true;
bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
return ret;
}
//+------------------------------------------------------------------+
//| 下降したティックであればtrue
//+------------------------------------------------------------------+
bool IsDescntTick()
{
static double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
bool ret = false;
if(SymbolInfoDouble(_Symbol, SYMBOL_BID) < bid)
ret = true;
bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
return ret;
}
//+------------------------------------------------------------------+
//| ストップのレートを計算する(引数1:ストップまでの距離(%) 引数2:買い(1)か売り(-1) )
//+------------------------------------------------------------------+
double CalculateStopRate(double range, int buysell)
{
if(range <= 0)
return (double)"nan";
if(buysell != 1 && buysell != -1){
Print("ストップのレート計算で不正な値を受け取りました。");
return (double)"nan";
}
double nowprice = iClose(_Symbol, PERIOD_CURRENT, 0);
return nowprice - (nowprice * range * buysell);
}
//+------------------------------------------------------------------+
//| 最後の約定価格を返す
//+------------------------------------------------------------------+
double GetLastDealPrice(long magic,ulong second = 600)
{
ulong ticket_history_deal = 0; // ディールチケット
double deal_price = (double)"nan";
if(!HistorySelect(TimeCurrent() - second, TimeCurrent()))
return deal_price;
uint total_deals = HistoryDealsTotal();
if(total_deals == 0)
return deal_price;
//--- 全ての取引を配列に取得
for(uint i = 0; i < total_deals; i++) {
if((ticket_history_deal = HistoryDealGetTicket(i)) > 0) {
if(HistoryDealGetInteger(ticket_history_deal, DEAL_MAGIC) != magic)
continue;
deal_price = HistoryDealGetDouble(ticket_history_deal, DEAL_PRICE);
}
}
return deal_price;
}
//+------------------------------------------------------------------+
//| 最後の約定時刻を返す
//+------------------------------------------------------------------+
datetime GetLastDealTime(long magic,ulong second = 3600)
{
ulong ticket_history_deal = 0; // ディールチケット
datetime deal_time = 0;
if(!HistorySelect(TimeCurrent() - second, TimeCurrent()))
return deal_time;
uint total_deals = HistoryDealsTotal();
if(total_deals == 0)
return deal_time;
//--- 全ての取引を配列に取得
for(uint i = 0; i < total_deals; i++) {
if((ticket_history_deal = HistoryDealGetTicket(i)) > 0) {
if(HistoryDealGetInteger(ticket_history_deal, DEAL_MAGIC) != magic)
continue;
deal_time = (datetime)HistoryDealGetInteger(ticket_history_deal, DEAL_TIME);
}
}
return deal_time;
}
//+------------------------------------------------------------------+
//| バックテスト結果をCSV出力する関数
//|
//| ファイルパス: \MetaQuotes\Tester\(MT5アカウントフォルダ)\Agent-127.0.0.1-3000\MQL5\Files
//| OnDeinit関数でCsvOutputBTResults(__FILE__)と書く
//+------------------------------------------------------------------+
bool OutputResultsToCSV(string ea_name = "BackTestEA")
{
//--- 単一バックテストのみ
if(!MQLInfoInteger(MQL_TESTER) || MQLInfoInteger(MQL_OPTIMIZATION))
return false;
//--- ファイル名
string fn = FileName(ea_name, TimeCurrent());
//--- ファイルハンドルの取得
int handle = FileOpen(fn + ".csv", FILE_CSV | FILE_WRITE);
if( handle == INVALID_HANDLE ) {
Print("CSV出力する関数内でファイルハンドル取得に失敗:", GetLastError());
return false;
}
long DealTimeIn[], DealTimeOut[], DealType[];
double DealPriceIn[], DealPriceOut[], DealVolume[], DealProfit[], DealSwap[];
string DealSymbol[];
int total_deals = 0;
//--- 取引損益を配列に書き込み
if(!GetTradeResults(DealTimeIn, DEAL_TIME, DEAL_ENTRY_IN)
|| !GetTradeResults(DealTimeOut, DEAL_TIME, DEAL_ENTRY_OUT)
|| !GetTradeResults(DealType, DEAL_TYPE, DEAL_ENTRY_IN)
|| !GetTradeResults(DealPriceIn, DEAL_PRICE, DEAL_ENTRY_IN)
|| !GetTradeResults(DealPriceOut, DEAL_PRICE, DEAL_ENTRY_OUT)
|| !GetTradeResults(DealVolume, DEAL_VOLUME, DEAL_ENTRY_OUT)
|| !GetTradeResults(DealProfit, DEAL_PROFIT, DEAL_ENTRY_OUT)
|| !GetTradeResults(DealSwap, DEAL_SWAP, DEAL_ENTRY_OUT)
|| !GetTradeResults(DealSymbol, DEAL_SYMBOL, DEAL_ENTRY_OUT) ){
FileClose(handle);
return false;
}
total_deals = ArraySize(DealProfit);
FileWrite(handle, "in_date", "in_time", "out_date", "out_time", "symbol", "buy_sell", "in_price", "out_price", "volume", "profit", "swap");
//--- CVSにデータを追加する
for(int i = 0; i < total_deals; i++) {
//--- ENUM_DEAL_TYPEをstring型の"Buy/Sell"で表現する
string deal_type = "Buy";
if(DEAL_TYPE_SELL == (ENUM_DEAL_TYPE)DealType[i])
deal_type = "Sell";
//--- 書き込み
FileWrite(handle,
TimeToString((datetime)DealTimeIn[i], TIME_DATE),
TimeToString((datetime)DealTimeIn[i], TIME_MINUTES),
TimeToString((datetime)DealTimeOut[i], TIME_DATE),
TimeToString((datetime)DealTimeOut[i], TIME_MINUTES),
DealSymbol[i],
deal_type,
DealPriceIn[i],
DealPriceOut[i],
DealVolume[i],
DealProfit[i],
DealSwap[i]);
}
FileClose(handle);
Print("CSV出力が完了しました");
return true;
}
//+------------------------------------------------------------------+
//| バックテスト結果をCSV出力する関数(日付細かく)
//|
//| ファイルパス: \MetaQuotes\Tester\(MT5アカウント)\Agent-127.0.0.1-3000\MQL5\Files
//| OnDeinit関数でOutputResultsToCSV(__FILE__)と書く
//+------------------------------------------------------------------+
bool OutputResultsToCSV2(string ea_name = "BackTestEA")
{
//--- 単一バックテストのみ
if(!MQLInfoInteger(MQL_TESTER) || MQLInfoInteger(MQL_OPTIMIZATION))
return false;
//--- ファイル名
string fn = FileName(ea_name, TimeCurrent());
//--- ファイルハンドルの取得
int handle = FileOpen(fn + ".csv", FILE_CSV | FILE_WRITE);
if( handle == INVALID_HANDLE ) {
Print("CSV出力する関数内でファイルハンドル取得に失敗:", GetLastError());
return false;
}
long DealTimeIn[], DealTimeOut[], DealType[];
double DealPriceIn[], DealPriceOut[], DealVolume[], DealProfit[], DealSwap[];
string DealSymbol[], DealComment[];
int total_deals = 0;
MqlDateTime dtin,dtout;
//--- 取引損益を配列に書き込み
if(!GetTradeResults(DealTimeIn, DEAL_TIME, DEAL_ENTRY_IN)
|| !GetTradeResults(DealTimeOut, DEAL_TIME, DEAL_ENTRY_OUT)
|| !GetTradeResults(DealType, DEAL_TYPE, DEAL_ENTRY_IN)
|| !GetTradeResults(DealPriceIn, DEAL_PRICE, DEAL_ENTRY_IN)
|| !GetTradeResults(DealPriceOut, DEAL_PRICE, DEAL_ENTRY_OUT)
|| !GetTradeResults(DealVolume, DEAL_VOLUME, DEAL_ENTRY_OUT)
|| !GetTradeResults(DealProfit, DEAL_PROFIT, DEAL_ENTRY_OUT)
|| !GetTradeResults(DealSwap, DEAL_SWAP, DEAL_ENTRY_OUT)
|| !GetTradeResults(DealSymbol, DEAL_SYMBOL, DEAL_ENTRY_OUT)
|| !GetTradeResults(DealComment, DEAL_COMMENT, DEAL_ENTRY_IN) ){
FileClose(handle);
return false;
}
total_deals = ArraySize(DealProfit);
FileWrite(handle,
"in年",
"in月",
"in日",
"in曜日",
"in時",
"in分",
"out年",
"out月",
"out日",
"out曜日",
"out時",
"out分",
"通貨ペア",
"Buy/Sell",
"in約定価格",
"out約定価格",
"ロット数",
"損益",
"スワップ",
"inコメント");
//--- CVSにデータを追加する
for(int i = 0; i < total_deals; i++) {
//--- ENUM_DEAL_TYPEをstring型の"Buy/Sell"で表現する
string deal_type = "Buy";
if(DEAL_TYPE_SELL == (ENUM_DEAL_TYPE)DealType[i])
deal_type = "Sell";
//---
TimeToStruct(DealTimeIn[i], dtin);
TimeToStruct(DealTimeOut[i], dtout);
//--- 書き込み
FileWrite(handle,
dtin.year,
dtin.mon,
dtin.day,
dtin.day_of_week,
dtin.hour,
dtin.min,
dtout.year,
dtout.mon,
dtout.day,
dtout.day_of_week,
dtout.hour,
dtout.min,
DealSymbol[i],
deal_type,
DealPriceIn[i],
DealPriceOut[i],
DealVolume[i],
DealProfit[i],
DealSwap[i],
DealComment[i]);
}
FileClose(handle);
Print("CSV出力が完了しました");
return true;
}
//+------------------------------------------------------------------+
//| ファイル名(名前とバックテスト終了日付)
//+------------------------------------------------------------------+
string FileName(string ea_name, datetime time)
{
string name = ea_name;
if(".mq5" == StringSubstr(name, StringFind(name, "."), 4)
|| ".ex5" == StringSubstr(name, StringFind(name, "."), 4)
|| ".mqh" == StringSubstr(name, StringFind(name, "."), 4)) {
StringSetLength(name, name.Length() - 4);
}
name += "_" + TimeToString(time, TIME_DATE);
StringReplace(name, ".", "");
StringReplace(name, " ", "_");
StringReplace(name, ":", "");
return name;
}
//+------------------------------------------------------------------+
//| long型の約定情報を配列に書き込む
//+------------------------------------------------------------------+
bool GetTradeResults(long &results[], const ENUM_DEAL_PROPERTY_INTEGER EDPI, const ENUM_DEAL_ENTRY EDE)
{
//--- 全期間の取引履歴をリクエストする
if(!HistorySelect(0, TimeCurrent()))
return (false);
uint total_deals = HistoryDealsTotal();
//--- 配列を、履歴の取引数にリサイズ
ArrayResize(results, total_deals);
int counter = 0; // 取引回数カウンター
ulong ticket_history_deal = 0; // ディールチケット
//--- 全ての取引を配列に取得
for(uint i = 0; i < total_deals; i++) {
//--- 取引を選択する
if((ticket_history_deal = HistoryDealGetTicket(i)) > 0) {
ENUM_DEAL_ENTRY deal_entry = (ENUM_DEAL_ENTRY)HistoryDealGetInteger(ticket_history_deal, DEAL_ENTRY);
long deal_type = HistoryDealGetInteger(ticket_history_deal, DEAL_TYPE);
long deal_info = HistoryDealGetInteger(ticket_history_deal, EDPI);
//--- 取引操作以外はスルー
if((deal_type != DEAL_TYPE_BUY) && (deal_type != DEAL_TYPE_SELL))
continue;
//--- ENUM_DEAL_ENTRYで指定した情報のみ
if(deal_entry == EDE) {
//--- 取引結果を配列に書き込み、取引のカウントアップ
results[counter] = deal_info;
counter++;
}
}
}
//--- 配列の最終サイズを設定する
ArrayResize(results, counter);
return (true);
}
//+------------------------------------------------------------------+
//| Double型の約定情報を配列に書き込む
//+------------------------------------------------------------------+
bool GetTradeResults(double &results[], const ENUM_DEAL_PROPERTY_DOUBLE EDPD, const ENUM_DEAL_ENTRY EDE)
{
//--- 全期間の取引履歴をリクエストする
if(!HistorySelect(0, TimeCurrent()))
return (false);
uint total_deals = HistoryDealsTotal();
//--- 配列を、履歴の取引数にリサイズ
ArrayResize(results, total_deals);
int counter = 0; // 取引回数カウンター
ulong ticket_history_deal = 0; // ディールチケット
//--- 全ての取引を配列に取得
for(uint i = 0; i < total_deals; i++) {
//--- 取引を選択する
if((ticket_history_deal = HistoryDealGetTicket(i)) > 0) {
ENUM_DEAL_ENTRY deal_entry = (ENUM_DEAL_ENTRY)HistoryDealGetInteger(ticket_history_deal, DEAL_ENTRY);
long deal_type = HistoryDealGetInteger(ticket_history_deal, DEAL_TYPE);
double deal_info = HistoryDealGetDouble(ticket_history_deal, EDPD);
//--- 取引操作以外はスルー
if((deal_type != DEAL_TYPE_BUY) && (deal_type != DEAL_TYPE_SELL))
continue;
//--- ENUM_DEAL_ENTRYで指定した情報のみ
if(deal_entry == EDE) {
//--- 取引結果を配列に書き込み、取引のカウントアップ
results[counter] = deal_info;
counter++;
}
}
}
//--- 配列の最終サイズを設定する
ArrayResize(results, counter);
return (true);
}
//+------------------------------------------------------------------+
//| string型の約定情報を配列に書き込む
//+------------------------------------------------------------------+
bool GetTradeResults(string &results[], const ENUM_DEAL_PROPERTY_STRING EDPS, const ENUM_DEAL_ENTRY EDE)
{
//--- 全期間の取引履歴をリクエストする
if(!HistorySelect(0, TimeCurrent()))
return (false);
uint total_deals = HistoryDealsTotal();
//--- 配列を、履歴の取引数にリサイズ
ArrayResize(results, total_deals);
int counter = 0; // 取引回数カウンター
ulong ticket_history_deal = 0; // ディールチケット
//--- 全ての取引を配列に取得
for(uint i = 0; i < total_deals; i++) {
//--- 取引を選択する
if((ticket_history_deal = HistoryDealGetTicket(i)) > 0) {
ENUM_DEAL_ENTRY deal_entry = (ENUM_DEAL_ENTRY)HistoryDealGetInteger(ticket_history_deal, DEAL_ENTRY);
long deal_type = HistoryDealGetInteger(ticket_history_deal, DEAL_TYPE);
string deal_info = HistoryDealGetString(ticket_history_deal, EDPS);
//--- 取引操作以外はスルー
if((deal_type != DEAL_TYPE_BUY) && (deal_type != DEAL_TYPE_SELL))
continue;
//--- ENUM_DEAL_ENTRYで指定した情報のみ
if(deal_entry == EDE) {
//--- 取引結果を配列に書き込み、取引のカウントアップ
results[counter] = deal_info;
counter++;
}
}
}
//--- 配列の最終サイズを設定する
ArrayResize(results, counter);
return (true);
}
//+------------------------------------------------------------------+