645 行
55 KiB
MQL5
645 行
55 KiB
MQL5
//+------------------------------------------------------------------+
|
|
//| TradingByHistoryDeals.mq5 |
|
|
//| Copyright 2024, MetaQuotes Ltd. |
|
|
//| https://www.mql5.com |
|
|
//+------------------------------------------------------------------+
|
|
#property copyright "Copyright 2024, MetaQuotes Ltd."
|
|
#property link "https://www.mql5.com"
|
|
#property version "1.00"
|
|
|
|
#include "SymbolTrade.mqh"
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Expert |
|
|
//+------------------------------------------------------------------+
|
|
//--- input parameters
|
|
input string InpTestedSymbol = ""; /* The symbol being tested in the tester */ // Тестируемый символ
|
|
input long InpTestedMagic = -1; /* The magic number being tested in the tester */ // Тестируемый магик
|
|
sinput bool InpShowDataInLog = false; /* Show collected data in the log */ // Показать собранные данные сделок в журнале
|
|
|
|
//--- global variables
|
|
CSymbolTrade SymbTradeTmp;
|
|
SDeal ExtArrayDeals[]={};
|
|
CArrayObj ExtListSymbols;
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Expert initialization function |
|
|
//+------------------------------------------------------------------+
|
|
int OnInit()
|
|
{
|
|
//--- Если советник запущен не в тестере
|
|
if(!MQLInfoInteger(MQL_TESTER))
|
|
{
|
|
//--- подготовим файл со всеми историческими сделками
|
|
if(!PreparesDealsHistoryFile(ExtArrayDeals))
|
|
return(INIT_FAILED);
|
|
|
|
//--- распечатаем в журнале все сделки после загрузки их из файла
|
|
if(InpShowDataInLog)
|
|
DealsArrayPrint(ExtArrayDeals);
|
|
|
|
//--- получаем первую балансовую сделку, создаём текст сообщения в выводим его при помощи Alert
|
|
SDeal deal=ExtArrayDeals[0];
|
|
long leverage=AccountInfoInteger(ACCOUNT_LEVERAGE);
|
|
double start_money=deal.profit;
|
|
datetime first_time=deal.time;
|
|
string start_time=TimeToString(deal.time, TIME_DATE);
|
|
string message=StringFormat("Now you can run testing\nInterval: %s - current date\nInitial deposit: %.2f, leverage 1:%I64u", start_time, start_money, leverage);
|
|
|
|
//--- сообщим алертом рекомендуемые параметры тестера стратегий для запуска тестирования
|
|
Alert(message);
|
|
}
|
|
//--- Советник запущен в тестере
|
|
else
|
|
{
|
|
//--- прочитаем данные из файла в массив
|
|
ulong file_size=0;
|
|
ArrayResize(ExtArrayDeals, 0);
|
|
if(!FileReadDealsToArray(ExtArrayDeals, file_size))
|
|
{
|
|
PrintFormat("Failed to read file \"%s\". Error %d", FILE_NAME, GetLastError());
|
|
return(INIT_FAILED);
|
|
}
|
|
|
|
//--- сообщим в журнале о количестве прочитанных байт из файла и о записи массива сделок.
|
|
PrintFormat("%I64u bytes were read from the file \"%s\" and written to the deals array. A total of %u deals were received", file_size, FILE_NAME, ExtArrayDeals.Size());
|
|
}
|
|
|
|
//--- Из массива исторических сделок создаём список торговых объектов по символам
|
|
if(!CreateListSymbolTrades(ExtArrayDeals, &ExtListSymbols))
|
|
{
|
|
Print("Errors found while creating symbol list");
|
|
return(INIT_FAILED);
|
|
}
|
|
//--- Распечатаем в журнале созданный список сделок
|
|
SymbolsArrayPrint(&ExtListSymbols);
|
|
|
|
//--- Обратимся к каждому символу для начала закачки исторических данных
|
|
//--- и открытия графиков проторгованных символов в тестере стратегий
|
|
datetime array[];
|
|
int total=ExtListSymbols.Total();
|
|
|
|
for(int i=0; i<total; i++)
|
|
{
|
|
CSymbolTrade *obj=ExtListSymbols.At(i);
|
|
if(obj==NULL)
|
|
continue;
|
|
CopyTime(obj.Symbol(), PERIOD_CURRENT, 0, 1, array);
|
|
}
|
|
|
|
//--- Всё успешно
|
|
return(INIT_SUCCEEDED);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Expert deinitialization function |
|
|
//+------------------------------------------------------------------+
|
|
void OnDeinit(const int reason)
|
|
{
|
|
//--- очищаем созданные списки и массивы
|
|
ExtListSymbols.Clear();
|
|
ArrayFree(ExtArrayDeals);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Expert tick function |
|
|
//+------------------------------------------------------------------+
|
|
void OnTick()
|
|
{
|
|
//--- работаем только в тестере стратегий
|
|
if(!MQLInfoInteger(MQL_TESTER))
|
|
return;
|
|
|
|
//--- Обрабатываем в тестере список сделок из файла
|
|
TradeByHistory(InpTestedSymbol, InpTestedMagic);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Tester function |
|
|
//+------------------------------------------------------------------+
|
|
double OnTester(void)
|
|
{
|
|
//--- посчитаем и вернём общее количество обработанных в тестере сделок
|
|
double ret=0.0;
|
|
int total=ExtListSymbols.Total();
|
|
for(int i=0; i<total; i++)
|
|
{
|
|
CSymbolTrade *obj=ExtListSymbols.At(i);
|
|
if(obj!=NULL)
|
|
ret+=obj.OnTester();
|
|
}
|
|
return(ret);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Сохраняет сделки из истории в массив |
|
|
//+------------------------------------------------------------------+
|
|
int SaveDealsToArray(SDeal &array[], bool logs=false)
|
|
{
|
|
//--- структура сделки
|
|
SDeal deal={};
|
|
|
|
//--- запросим историю сделок в интервале с самого начала по текущий момент
|
|
if(!HistorySelect(0, TimeCurrent()))
|
|
{
|
|
Print("HistorySelect() failed. Error ", GetLastError());
|
|
return 0;
|
|
}
|
|
|
|
//--- общее количество сделок в списке
|
|
int total=HistoryDealsTotal();
|
|
|
|
//--- обработаем каждую сделку
|
|
for(int i=0; i<total; i++)
|
|
{
|
|
//--- получаем тикет очередной сделки (сделка автоматически выбирается для получения её свойств)
|
|
ulong ticket=HistoryDealGetTicket(i);
|
|
if(ticket==0)
|
|
continue;
|
|
|
|
//--- сохраняем только балансовые и торговые сделки
|
|
ENUM_DEAL_TYPE deal_type=(ENUM_DEAL_TYPE)HistoryDealGetInteger(ticket, DEAL_TYPE);
|
|
if(deal_type!=DEAL_TYPE_BUY && deal_type!=DEAL_TYPE_SELL && deal_type!=DEAL_TYPE_BALANCE)
|
|
continue;
|
|
|
|
//--- сохраняем свойства сделки в структуре
|
|
deal.ticket=ticket;
|
|
deal.type=deal_type;
|
|
deal.order=HistoryDealGetInteger(ticket, DEAL_ORDER);
|
|
deal.entry=(ENUM_DEAL_ENTRY)HistoryDealGetInteger(ticket, DEAL_ENTRY);
|
|
deal.reason=(ENUM_DEAL_REASON)HistoryDealGetInteger(ticket, DEAL_REASON);
|
|
deal.time=(datetime)HistoryDealGetInteger(ticket, DEAL_TIME);
|
|
deal.time_msc=HistoryDealGetInteger(ticket, DEAL_TIME_MSC);
|
|
deal.pos_id=HistoryDealGetInteger(ticket, DEAL_POSITION_ID);
|
|
deal.volume=HistoryDealGetDouble(ticket, DEAL_VOLUME);
|
|
deal.price=HistoryDealGetDouble(ticket, DEAL_PRICE);
|
|
deal.profit=HistoryDealGetDouble(ticket, DEAL_PROFIT);
|
|
deal.commission=HistoryDealGetDouble(ticket, DEAL_COMMISSION);
|
|
deal.swap=HistoryDealGetDouble(ticket, DEAL_SWAP);
|
|
deal.fee=HistoryDealGetDouble(ticket, DEAL_FEE);
|
|
deal.sl=HistoryDealGetDouble(ticket, DEAL_SL);
|
|
deal.tp=HistoryDealGetDouble(ticket, DEAL_TP);
|
|
deal.magic=HistoryDealGetInteger(ticket, DEAL_MAGIC);
|
|
deal.SetSymbol(HistoryDealGetString(ticket, DEAL_SYMBOL));
|
|
deal.SetComment(HistoryDealGetString(ticket, DEAL_COMMENT));
|
|
deal.SetExternalID(HistoryDealGetString(ticket, DEAL_EXTERNAL_ID));
|
|
deal.digits=(int)SymbolInfoInteger(deal.Symbol(), SYMBOL_DIGITS);
|
|
|
|
//--- увеличиваем массив и
|
|
int size=(int)array.Size();
|
|
ResetLastError();
|
|
if(ArrayResize(array, size+1, total)!=size+1)
|
|
{
|
|
Print("ArrayResize() failed. Error ", GetLastError());
|
|
continue;
|
|
}
|
|
//--- сохраняем в массиве сделку
|
|
array[size]=deal;
|
|
//--- если разрешено, выводим описание сохранённой сделки в журнал
|
|
if(logs)
|
|
DealPrint(deal, i);
|
|
}
|
|
//--- возвращаем количество сохранённых в массиве сделок
|
|
return (int)array.Size();
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Выводит сделки из массива в журнал |
|
|
//+------------------------------------------------------------------+
|
|
void DealsArrayPrint(SDeal &array[])
|
|
{
|
|
int total=(int)array.Size();
|
|
//--- если передан пустой массив - сообщаем об этом и возвращаем false
|
|
if(total==0)
|
|
{
|
|
PrintFormat("%s: Error! Empty deals array passed",__FUNCTION__);
|
|
return;
|
|
}
|
|
//--- В цикле по массиву сделок распечатаем описание каждой сделки
|
|
for(int i=0; i<total; i++)
|
|
{
|
|
DealPrint(array[i], i);
|
|
}
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Возвращает описание типа сделки |
|
|
//+------------------------------------------------------------------+
|
|
string DealTypeDescription(const ENUM_DEAL_TYPE type)
|
|
{
|
|
switch(type)
|
|
{
|
|
case DEAL_TYPE_BUY : return "Buy";
|
|
case DEAL_TYPE_SELL : return "Sell";
|
|
case DEAL_TYPE_BALANCE : return "Balance";
|
|
case DEAL_TYPE_CREDIT : return "Credit";
|
|
case DEAL_TYPE_CHARGE : return "Additional charge";
|
|
case DEAL_TYPE_CORRECTION : return "Correction";
|
|
case DEAL_TYPE_BONUS : return "Bonus";
|
|
case DEAL_TYPE_COMMISSION : return "Additional commission";
|
|
case DEAL_TYPE_COMMISSION_DAILY : return "Daily commission";
|
|
case DEAL_TYPE_COMMISSION_MONTHLY : return "Monthly commission";
|
|
case DEAL_TYPE_COMMISSION_AGENT_DAILY : return "Daily agent commission";
|
|
case DEAL_TYPE_COMMISSION_AGENT_MONTHLY: return "Monthly agent commission";
|
|
case DEAL_TYPE_INTEREST : return "Interest rate";
|
|
case DEAL_TYPE_BUY_CANCELED : return "Canceled buy deal";
|
|
case DEAL_TYPE_SELL_CANCELED : return "Canceled sell deal";
|
|
case DEAL_DIVIDEND : return "Dividend operations";
|
|
case DEAL_DIVIDEND_FRANKED : return "Franked (non-taxable) dividend operations";
|
|
case DEAL_TAX : return "Tax charges";
|
|
default : return "Unknown deal type: "+(string)type;
|
|
}
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Возвращает описание способа изменения позиции |
|
|
//+------------------------------------------------------------------+
|
|
string DealEntryDescription(const ENUM_DEAL_ENTRY entry)
|
|
{
|
|
switch(entry)
|
|
{
|
|
case DEAL_ENTRY_IN : return "Entry In";
|
|
case DEAL_ENTRY_OUT : return "Entry Out";
|
|
case DEAL_ENTRY_INOUT : return "Entry InOut";
|
|
case DEAL_ENTRY_OUT_BY : return "Entry OutBy";
|
|
default : return "Unknown entry: "+(string)entry;
|
|
}
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Возвращает описание сделки |
|
|
//+------------------------------------------------------------------+
|
|
string DealDescription(SDeal &deal, const int index)
|
|
{
|
|
string indexs=StringFormat("% 5d", index);
|
|
if(deal.type!=DEAL_TYPE_BALANCE)
|
|
return(StringFormat("%s: deal #%I64u %s, type %s, Position #%I64d %s (magic %I64d), Price %.*f at %s, sl %.*f, tp %.*f",
|
|
indexs, deal.ticket, DealEntryDescription(deal.entry), DealTypeDescription(deal.type),
|
|
deal.pos_id, deal.Symbol(), deal.magic, deal.digits, deal.price,
|
|
TimeToString(deal.time, TIME_DATE|TIME_MINUTES|TIME_SECONDS), deal.digits, deal.sl, deal.digits, deal.tp));
|
|
else
|
|
return(StringFormat("%s: deal #%I64u %s, type %s %.2f %s at %s",
|
|
indexs, deal.ticket, DealEntryDescription(deal.entry), DealTypeDescription(deal.type),
|
|
deal.profit, AccountInfoString(ACCOUNT_CURRENCY), TimeToString(deal.time)));
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Возвращает описание сделки |
|
|
//+------------------------------------------------------------------+
|
|
string DealDescription(CDeal *deal, const int index)
|
|
{
|
|
string indexs=StringFormat("% 5d", index);
|
|
if(deal.TypeDeal()!=DEAL_TYPE_BALANCE)
|
|
return(StringFormat("%s: deal #%I64u %s, type %s, Position #%I64d %s (magic %I64d), Price %.*f at %s, sl %.*f, tp %.*f",
|
|
indexs, deal.Ticket(), DealEntryDescription(deal.Entry()), DealTypeDescription(deal.TypeDeal()),
|
|
deal.PositionID(), deal.Symbol(), deal.Magic(), deal.Digits(), deal.Price(),
|
|
TimeToString(deal.Time(), TIME_DATE|TIME_MINUTES|TIME_SECONDS), deal.Digits(), deal.SL(), deal.Digits(), deal.TP()));
|
|
else
|
|
return(StringFormat("%s: deal #%I64u %s, type %s %.2f %s at %s",
|
|
indexs, deal.Ticket(), DealEntryDescription(deal.Entry()), DealTypeDescription(deal.TypeDeal()),
|
|
deal.Profit(), AccountInfoString(ACCOUNT_CURRENCY), TimeToString(deal.Time())));
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Распечатывает в журнале данные сделки |
|
|
//+------------------------------------------------------------------+
|
|
void DealPrint(SDeal &deal, const int index)
|
|
{
|
|
Print(DealDescription(deal, index));
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Открывает файл для записи, возвращает хэндл |
|
|
//+------------------------------------------------------------------+
|
|
bool FileOpenToWrite(int &handle)
|
|
{
|
|
ResetLastError();
|
|
handle=FileOpen(PATH, FILE_WRITE|FILE_BIN|FILE_COMMON);
|
|
if(handle==INVALID_HANDLE)
|
|
{
|
|
PrintFormat("%s: FileOpen() failed. Error %d",__FUNCTION__, GetLastError());
|
|
return false;
|
|
}
|
|
//--- успешно
|
|
return true;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Открывает файл для чтения, возвращает хэндл |
|
|
//+------------------------------------------------------------------+
|
|
bool FileOpenToRead(int &handle)
|
|
{
|
|
ResetLastError();
|
|
handle=FileOpen(PATH, FILE_READ|FILE_BIN|FILE_COMMON);
|
|
if(handle==INVALID_HANDLE)
|
|
{
|
|
PrintFormat("%s: FileOpen() failed. Error %d",__FUNCTION__, GetLastError());
|
|
return false;
|
|
}
|
|
//--- успешно
|
|
return true;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Сохраняет в файл данные сделок из массива |
|
|
//+------------------------------------------------------------------+
|
|
bool FileWriteDealsFromArray(SDeal &array[], ulong &file_size)
|
|
{
|
|
//--- если передан пустой массив - сообщаем об этом и возвращаем false
|
|
if(array.Size()==0)
|
|
{
|
|
PrintFormat("%s: Error! Empty deals array passed",__FUNCTION__);
|
|
return false;
|
|
}
|
|
|
|
//--- откроем файл для записи, получим его хэндл
|
|
int handle=INVALID_HANDLE;
|
|
if(!FileOpenToWrite(handle))
|
|
return false;
|
|
|
|
//--- переместим файловый указатель на конец файла
|
|
bool res=true;
|
|
ResetLastError();
|
|
res&=FileSeek(handle, 0, SEEK_END);
|
|
if(!res)
|
|
PrintFormat("%s: FileSeek(SEEK_END) failed. Error %d",__FUNCTION__, GetLastError());
|
|
|
|
//--- запишем данные массива в конец файла
|
|
file_size=0;
|
|
res&=(FileWriteArray(handle, array)==array.Size());
|
|
if(!res)
|
|
PrintFormat("%s: FileWriteArray() failed. Error ",__FUNCTION__, GetLastError());
|
|
else
|
|
file_size=FileSize(handle);
|
|
|
|
//--- закрываем файл
|
|
FileClose(handle);
|
|
return res;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Загружает в массив данные сделок из файла |
|
|
//+------------------------------------------------------------------+
|
|
bool FileReadDealsToArray(SDeal &array[], ulong &file_size)
|
|
{
|
|
//--- откроем файл для чтения, получим его хэндл
|
|
int handle=INVALID_HANDLE;
|
|
if(!FileOpenToRead(handle))
|
|
return false;
|
|
|
|
//--- переместим файловый указатель на конец файла
|
|
bool res=true;
|
|
ResetLastError();
|
|
|
|
//--- прочитаем данные из файла в массив
|
|
file_size=0;
|
|
res=(FileReadArray(handle, array)>0);
|
|
if(!res)
|
|
PrintFormat("%s: FileWriteArray() failed. Error ",__FUNCTION__, GetLastError());
|
|
else
|
|
file_size=FileSize(handle);
|
|
|
|
//--- закрываем файл
|
|
FileClose(handle);
|
|
return res;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Подготавливает файл со сделками истории |
|
|
//+------------------------------------------------------------------+
|
|
bool PreparesDealsHistoryFile(SDeal &deals_array[])
|
|
{
|
|
//--- сохраним все сделки счёта в массив сделок
|
|
int total=SaveDealsToArray(deals_array);
|
|
if(total==0)
|
|
return false;
|
|
|
|
//--- запишем данные массива сделок в файл
|
|
ulong file_size=0;
|
|
if(!FileWriteDealsFromArray(deals_array, file_size))
|
|
return false;
|
|
|
|
//--- распечатаем в журнале сколько сделок было прочитано и сохранено в файл, путь к файлу и его размер
|
|
PrintFormat("%u deals were saved in an array and written to a \"%s\" file of %I64u bytes in size",
|
|
deals_array.Size(), "TERMINAL_COMMONDATA_PATH\\Files\\"+ PATH, file_size);
|
|
|
|
//--- теперь для проверки прочитаем данные из файла в массив
|
|
ArrayResize(deals_array, 0, total);
|
|
if(!FileReadDealsToArray(deals_array, file_size))
|
|
return false;
|
|
|
|
//--- распечатаем в журнале сколько байт было прочитано из файла и количество полученных в массив сделок
|
|
PrintFormat("%I64u bytes were read from the file \"%s\" and written to the deals array. A total of %u deals were received", file_size, FILE_NAME, deals_array.Size());
|
|
return true;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Создаёт объект сделки из структуры |
|
|
//+------------------------------------------------------------------+
|
|
CDeal *CreateDeal(SDeal &deal_str)
|
|
{
|
|
//--- Если объект сделки создать не удалось - сообщаем в журнале об ошибке и возвращаем NULL
|
|
CDeal *deal=new CDeal(deal_str.ticket, deal_str.Symbol());
|
|
if(deal==NULL)
|
|
{
|
|
PrintFormat("%s: Error. Failed to create deal object");
|
|
return NULL;
|
|
}
|
|
//--- заполняем свойства сделки из полей структуры
|
|
deal.SetOrder(deal_str.order); // Ордер, на основании которого была открыта сделка
|
|
deal.SetPositionID(deal_str.pos_id); // Идентификатор позиции
|
|
deal.SetTimeMsc(deal_str.time_msc); // Время в миллисекундах
|
|
deal.SetTime(deal_str.time); // Время
|
|
deal.SetVolume(deal_str.volume); // Объём
|
|
deal.SetPrice(deal_str.price); // Цена
|
|
deal.SetProfit(deal_str.profit); // Прибыль
|
|
deal.SetCommission(deal_str.commission); // Комиссия по сделке
|
|
deal.SetSwap(deal_str.swap); // Накопленный своп при закрытии
|
|
deal.SetFee(deal_str.fee); // Оплата за проведение сделки, начисляется сразу после совершения сделки
|
|
deal.SetSL(deal_str.sl); // Уровень Stop Loss
|
|
deal.SetTP(deal_str.tp); // Уровень Take Profit
|
|
deal.SetType(deal_str.type); // Тип
|
|
deal.SetEntry(deal_str.entry); // Способ изменения позиции
|
|
deal.SetReason(deal_str.reason); // Причина или источник проведения сделки
|
|
deal.SetMagic(deal_str.magic); // Идентификатор эксперта
|
|
deal.SetComment(deal_str.Comment()); // Комментарий к сделке
|
|
deal.SetExternalID(deal_str.ExternalID()); // Идентификатор сделки во внешней торговой системе (на бирже)
|
|
//--- Возвращаем указатель на созданный объект
|
|
return deal;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Создаёт массив используемых символов |
|
|
//+------------------------------------------------------------------+
|
|
bool CreateListSymbolTrades(SDeal &array_deals[], CArrayObj *list_symbols)
|
|
{
|
|
bool res=true; // результат
|
|
int total=(int)array_deals.Size(); // общее количество сделок в массиве
|
|
|
|
//--- если массив сделок пустой - возвращаем false
|
|
if(total==0)
|
|
{
|
|
PrintFormat("%s: Error! Empty deals array passed",__FUNCTION__);
|
|
return false;
|
|
}
|
|
|
|
//--- в цикле по массиву сделок
|
|
CSymbolTrade *SymbolTrade=NULL;
|
|
for(int i=0; i<total; i++)
|
|
{
|
|
//--- получаем очередную сделку и, если это не покупка и не продажа - идём к следующей
|
|
SDeal deal_str=array_deals[i];
|
|
if(deal_str.type!=DEAL_TYPE_BUY && deal_str.type!=DEAL_TYPE_SELL)
|
|
continue;
|
|
|
|
//--- найдём торговый объект в списке, у которого символ равен символу сделки
|
|
string symbol=deal_str.Symbol();
|
|
SymbTradeTmp.SetSymbol(symbol);
|
|
list_symbols.Sort();
|
|
int index=list_symbols.Search(&SymbTradeTmp);
|
|
|
|
//--- если индекс искомого объекта в списке равен -1 - такого объекта в списке нет
|
|
if(index==WRONG_VALUE)
|
|
{
|
|
//--- создаём новый торговый объект символа и, если создать не получилось -
|
|
//--- добавляем к результату значение false и идём к следующей сделке
|
|
SymbolTrade=new CSymbolTrade(symbol);
|
|
if(SymbolTrade==NULL)
|
|
{
|
|
res &=false;
|
|
continue;
|
|
}
|
|
//--- если торговый объект символа не удалось добавить в список -
|
|
//--- удаляем вновь созданный объект, добавляем к результату значение false
|
|
//--- и идём к следующей сделке
|
|
if(!list_symbols.Add(SymbolTrade))
|
|
{
|
|
delete SymbolTrade;
|
|
res &=false;
|
|
continue;
|
|
}
|
|
}
|
|
//--- иначе, если торговый объект уже существует в списке - получаем его по индексу
|
|
else
|
|
{
|
|
SymbolTrade=list_symbols.At(index);
|
|
if(SymbolTrade==NULL)
|
|
continue;
|
|
}
|
|
|
|
//--- если текущей сделки ещё нет в списке сделок торгового объекта символа
|
|
if(SymbolTrade.GetDealByTime(deal_str.time)==NULL)
|
|
{
|
|
//--- создаём объект сделки по её образцу-структуре
|
|
CDeal *deal=CreateDeal(deal_str);
|
|
if(deal==NULL)
|
|
{
|
|
res &=false;
|
|
continue;
|
|
}
|
|
//--- к значению результата добавляем результат добавления объекта сделки в список сделок торгового объекта символа
|
|
res &=SymbolTrade.AddDeal(deal);
|
|
}
|
|
}
|
|
//--- возвращаем итоговый результат создания торговых объектов и добавления сделок в их списки
|
|
return res;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Выводит в журнал список торговых объектов символов |
|
|
//+------------------------------------------------------------------+
|
|
void SymbolsArrayPrint(CArrayObj *list_symbols)
|
|
{
|
|
int total=list_symbols.Total();
|
|
if(total==0)
|
|
return;
|
|
Print("Symbols used in trading:");
|
|
for(int i=0; i<total; i++)
|
|
{
|
|
string index=StringFormat("% 3d", i+1);
|
|
CSymbolTrade *obj=list_symbols.At(i);
|
|
if(obj==NULL)
|
|
continue;
|
|
PrintFormat("%s. %s",index, obj.Description());
|
|
}
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Торговля по истории |
|
|
//+------------------------------------------------------------------+
|
|
void TradeByHistory(const string symbol="", const long magic=-1)
|
|
{
|
|
datetime time=0;
|
|
int total=ExtListSymbols.Total(); // количество торговых объектов в списке
|
|
|
|
//--- в цикле по всем торговым объектам символов
|
|
for(int i=0; i<total; i++)
|
|
{
|
|
//--- получаем очередной торговый объект
|
|
CSymbolTrade *obj=ExtListSymbols.At(i);
|
|
if(obj==NULL)
|
|
continue;
|
|
|
|
//--- получаем текущую сделку, на которую указывает индекс списка сделок
|
|
CDeal *deal=obj.GetDealCurrent();
|
|
if(deal==NULL)
|
|
continue;
|
|
|
|
//--- фильтруем сделку по магику и символу
|
|
if((magic>-1 && deal.Magic()!=magic) || (symbol!="" && deal.Symbol()!=symbol))
|
|
continue;
|
|
|
|
//--- фильтруем сделку по типу (только сделки покупки/продажи)
|
|
ENUM_DEAL_TYPE type=deal.TypeDeal();
|
|
if(type!=DEAL_TYPE_BUY && type!=DEAL_TYPE_SELL)
|
|
continue;
|
|
|
|
//--- если это уже обработанная в тестере сделка - идём к следующей
|
|
if(deal.TicketTester()>0)
|
|
continue;
|
|
|
|
//--- если время сделки ещё не настало - идём к следующему торговому объекту следующего символа
|
|
if(!obj.CheckTime(deal.Time()))
|
|
continue;
|
|
|
|
//--- если сделка входа в рынок
|
|
ENUM_DEAL_ENTRY entry=deal.Entry();
|
|
if(entry==DEAL_ENTRY_IN)
|
|
{
|
|
//--- открываем позицию по типу сделки
|
|
double sl=0;
|
|
double tp=0;
|
|
ulong ticket=(type==DEAL_TYPE_BUY ? obj.Buy(deal.Volume(), deal.Magic(), sl, tp, deal.Comment()) :
|
|
type==DEAL_TYPE_SELL ? obj.Sell(deal.Volume(),deal.Magic(), sl, tp, deal.Comment()) : 0);
|
|
|
|
//--- если позиция открыта (получили её тикет)
|
|
if(ticket>0)
|
|
{
|
|
//--- увеличиваем количество обработанных тестером сделок и записываем тикет сделки в тестере в свойства объекта сделки
|
|
obj.SetNumProcessedDeals(obj.NumProcessedDeals()+1);
|
|
deal.SetTicketTester(ticket);
|
|
//--- получаем идентификатор позиции в тестере и записываем его в свойства объекта сделки
|
|
long pos_id_tester=0;
|
|
if(HistoryDealSelect(ticket))
|
|
{
|
|
pos_id_tester=HistoryDealGetInteger(ticket, DEAL_POSITION_ID);
|
|
deal.SetPosIDTester(pos_id_tester);
|
|
}
|
|
}
|
|
}
|
|
|
|
//--- если сделка выхода из рынка
|
|
if(entry==DEAL_ENTRY_OUT || entry==DEAL_ENTRY_INOUT || entry==DEAL_ENTRY_OUT_BY)
|
|
{
|
|
//--- получаем сделку, на основании которой была открыта позиция
|
|
CDeal *deal_in=obj.GetDealInByPosID(deal.PositionID());
|
|
if(deal_in==NULL)
|
|
continue;
|
|
|
|
//--- получаем тикет позиции в тестере из свойств открывающей сделки
|
|
//--- если тикет равен нулю, значит скорее всего позиция в тестере уже закрыта
|
|
ulong ticket_tester=deal_in.TicketTester();
|
|
if(ticket_tester==0)
|
|
{
|
|
PrintFormat("Could not get position ticket, apparently position #%I64d (#%I64d) is already closed \n", deal.PositionID(), deal_in.PosIDTester());
|
|
obj.SetNextDealIndex();
|
|
continue;
|
|
}
|
|
//--- если позиция закрыта по тикету
|
|
if(obj.ClosePos(ticket_tester))
|
|
{
|
|
//--- увеличиваем количество обработанных тестером сделок и записываем тикет сделки в тестере в свойства объекта сделки
|
|
obj.SetNumProcessedDeals(obj.NumProcessedDeals()+1);
|
|
deal.SetTicketTester(ticket_tester);
|
|
}
|
|
}
|
|
//--- если теперь в объекте сделки записан тикет - значит сделка успешно обработана -
|
|
//--- устанавливаем индекс сделки в списке на следующую сделку
|
|
if(deal.TicketTester()>0)
|
|
{
|
|
obj.SetNextDealIndex();
|
|
}
|
|
}
|
|
}
|
|
//+------------------------------------------------------------------+
|