Random Trading
//+------------------------------------------------------------------+//| Random.mq4 |//| amba |//| 2009-12-07 |//+------------------------------------------------------------------+ /* Простой скрипт для иллюстрации виртуальной мультивалютной торговли. Запускаем его на любой валюте. При этом торговля будет вестить по валютам, указанным в массиве. Требуется наличие котировок по выбранным инструментам периода текущего графика. Рекомендую М15. */#property copyright "amba"#property link "http://www.mql4.com/ru/users/Amba"#property show_inputs extern datetime date.start=D'2009.11.01'; extern datetime date.end= D'2009.12.01'; extern double SL = 0.50; extern double TP = 0.50; extern bool IsPercent = true; #include <ArrayVO.mq4> int MagicNum=0; datetime LastDT=0; // торгуемые инструментыstring symb[]={ "USDJPY","EURUSD", "EURGBP"};//, "GBPUSD", "USDCHF"};};// //+------------------------------------------------------------------+//| expert initialization function |//+------------------------------------------------------------------+int init(){ MagicNum=GetTickCount(); MathSrand(GetTickCount()); return(0); } //+------------------------------------------------------------------+//| expert deinitialization function |//+------------------------------------------------------------------+int deinit(){ // закрытие всех открытых v.CloseAllOrders(); // вывод массивов в CSV. // %METATRADER_FOLDER%\experts\files\deb.Random.hist.csv содержит историю торговли // %METATRADER_FOLDER%\experts\files\deb.Random.trade.csv если всё закрыли как положено - он пуст DebugPrintArrays("Random"); return(0); }//+------------------------------------------------------------------+//| expert start function |//+------------------------------------------------------------------+int start(){ int _per=Period()*60; datetime dt=date.start-_per; while(date.end>dt) { dt+=_per; // Отобразим ход выполнения string cmnt = StringConcatenate("Current: ",TimeToStr(dt,TIME_DATE),"\nIn trade: ",v.OrdersTotal(),"\nIn hist: ",v.OrdersHistoryTotal()); Comment(cmnt); // пересчет массива открытых ордеров на каждом баре RecalcTradeArray(dt); if(v.OrdersTotal()>0) continue; // случайным образом выбираем направление торговли Бай/Селл int op=MathRound(MathRand()/32767.0); int op1=1-op; // сигнал, противоположный выбранному // случайным образом выбираем инструмент из числа предопределенных int isymb = MathRound((ArraySize(symb)-1)*MathRand()/32767.0); string sy = symb[isymb]; double pp,sl,tp; // Цены открытия, стоп-лосс и тэйк-профит Print("Operation: ", op, " symbol ",sy); // определяем смещение бара int sh=iBarShift(sy,0,dt,true); // Если бар не нашли - продолжим if(sh<0) continue; int spread=MarketInfo(sy,MODE_SPREAD); double _point=MarketInfo(sy,MODE_POINT); // считаем цену открытия бара ценой открытия ордера pp=iOpen(sy,0,sh)+spread*op1*_point; if(IsPercent) { sl=pp * (1 - IIF(op==OP_BUY,1,-1) * SL/100); tp=pp * (1 + IIF(op==OP_BUY,1,-1) * TP/100) ; } else { sl=pp-IIF(op==OP_BUY,1,-1)* SL *_point; tp=pp+IIF(op==OP_BUY,1,-1)* TP *_point; } // установка "текущего времени" для эмуляции сделок SetCurrentDateTime(dt); v.SetOrder(sy, op, 0.1,pp,sl ,tp, MagicNum, dt+86400, StringConcatenate("Params",csv.dem,SL,csv.dem,TP)); } return(0); } //+------------------------------------------------------------------+
//+------------------------------------------------------------------+//| ArrayVO.mq4 |//| amba |//| 2009-12-12 |//| ver. 1.03 |//| Библиотека предназначена для ведения виртуальной торговли. |//| |//| Реализована замена стандартных функций по работе с ордерами |//| Order*() на аналогичные v.Order*(). |//| |//| Реализованы функции загрузки/выгрузки массивов ордеров в бинарном|//| и текстовом виде. |//| |//| В библиотеке использованы незначительно модифицированные функции |//| (автор Ким Игорь В. aka KimIV, http://www.kimiv.ru) по работе с |//| ордерами, а также идея работы с массивом номеров предварительно |//|отфильтрованных ордеров (автора не знаю, но тоже очень благодарен)| |//| |//| |//+------------------------------------------------------------------+#property copyright "amba"#property link "http://www.mql4.com/ru/users/Amba"//#property library#include <stdlib.mqh> //количество колонок в массивах ордеров#define MAX_FIELDS 17 // массивы ордеров действующих и закрытых// значения типа doubledouble aHistory[][MAX_FIELDS], aTrade[][MAX_FIELDS]; // названия символов и комментарии к ордерамstring aHistory.strings[][2], aTrade.strings[][2]; // счетчики количества ордеровint aHistory.cnt = 0, aTrade.cnt = 0; datetime aTrade.CurrentDT=0; // константы номеров колонок массивов// стандартные параметры ордеров#define PROP.Ticket 0#define PROP.OpenDT 1#define PROP.Type 2#define PROP.Lots 3#define PROP.OpenPrice 4#define PROP.SL 5#define PROP.TP 6#define PROP.Magic 7#define PROP.ExpDT 8#define PROP.ClosePrice 9#define PROP.CloseDT 10#define PROP.Profit 11 // в валюте// дополнительные параметры ордеров#define PROP.LastRecalcDT 12 // дата/время последнего пересчета ордера#define PROP.AccBalance 13 // в валюте#define PROP.AccEquity 14 // в валюте#define PROP.MaxDD 15 // в пунктах#define PROP.MaxProfit 16 // в пунктах// константы номеров колонок строковых массивов#define PROP.Symbol 0#define PROP.Comment 1 int Slippage = 5; // Проскальзывание цены - рудимент от реальной торговли string csv.dem = ","; // CSV разделитель int aTrade.p=-1; // указатель позиции в массиве текущих ордеровint aHistory.p=-1; // указатель позиции в массиве закрытых ордеровint who.selected=0; // селектор вида массива {MODE_TRADES|MODE_HISTORY} int next_t=0; // счетчик генератора номеров ордеров bool aTrade.CalcBalance = false; // Флаг расчета баланса и эквити //+------------------------------------------------------------------+//| Группа функций по работе с ордерами |//+------------------------------------------------------------------+ // константы определяют использование различных ГРУПП операций ордеров:#define TICKET_ORD -3 // отложенные ордера - OP_BUYLIMIT OP_SELLLIMIT OP_BUYSTOP OP_SELLSTOP#define TICKET_POS -2 // открытые позиции - OP_BUY OP_SELL#define TICKET_ALL -1 // любой ордер //+------------------------------------------------------------------+//| Проверяет соответствие текущего выбранного ордера указанным в |//| параметрах условиям |//| Возвращаемые значения: true|false (соответствует|нет) |//| Параметры: |//| (дефолтные значения означают отсутствие условий по данному |//| признаку) |//| sy - название символа |//| (напр. "EURUSD", или "0" - текущий, "" - любой) |//| op - тип ордера |//| op={[OP_BUY..OP_SELLSTOP]|TICKET_POS|TICKET_ORD|TICKET_ALL} |//| mn - Magic Number |//| ot - время открытия. Будут выбраны ордера с временем открытия, |//| меньшим или равным указанному |//| |//| Используется в функциях перебора, фильтрации ордеров |//+------------------------------------------------------------------+bool v.IsOrderFor(string sy="", int op=-1, int mn=-1, datetime ot=0){ int ty=v.OrderType(); if (sy=="0") sy=Symbol(); if ((v.OrderSymbol()==sy || sy=="") && (ty==op || op==TICKET_ALL || (op==TICKET_POS && ty>=0 && ty<2) || (op==TICKET_ORD && ty>1 && ty<6) ) ) if (mn<0 || v.OrderMagicNumber()==mn) if (ot<=v.OrderOpenTime()) return(true); return(false); } //+------------------------------------------------------------------+//| По заданным условиям проверяет - есть ли хотя бы один ордер, со- |//| ответствующий условиям поиска |//| Возвращаемые значения: true|false (есть|нет) |//| Параметры: см. описание IsOrderFor() |//| |//+------------------------------------------------------------------+bool v.ExistOrders(string sy="", int op=-1, int mn=-1, datetime ot=0){ int i, k=v.OrdersTotal(), c=0; for (i=0; i<k; i++) if (v.OrderSelect(i, SELECT_BY_POS, MODE_TRADES)==true) if(v.IsOrderFor(sy,op,mn,ot)) return(true); return(false); } //+------------------------------------------------------------------+//| По заданным условиям подсчитывает - сколько ордеров соответствует|//| условиям поиска |//| Возвращаемые значения: количество ордеров |//| Параметры: см. описание IsOrderFor() |//| |//+------------------------------------------------------------------+int v.CountAllOrders(string sy="", int op=-1, int mn=-1, datetime ot=0){ int i, k=v.OrdersTotal(), c=0; for (i=0; i<k; i++) if (v.OrderSelect(i, SELECT_BY_POS, MODE_TRADES)==true) if(v.IsOrderFor(sy,op,mn,ot)==true) c++; return(c); } //+------------------------------------------------------------------+//| По заданным условиям ищет ордера и заполняет переданный массив |//| номерами найденных ордеров |//| Возвращаемые значения: количество ордеров |//| Параметры: |//| Ticket - одномерный массив, заполняется номерами ордеров | //| остальные параметры см. описание IsOrderFor() |//| |//+------------------------------------------------------------------+int v.CreateTicketArray(int& Ticket[], string sy="", int op=-1, int mn=-1, datetime ot=0){ int total=v.OrdersTotal(), i, c=0; if (total<=0) return (0); for(i=0;i<total;i++) if(v.OrderSelect(i, SELECT_BY_POS)==true) if(v.IsOrderFor(sy,op,mn,ot)==true) {ArrayResize(Ticket,c+1);Ticket[c] = v.OrderTicket(); c++; } return (c); } //+------------------------------------------------------------------+//| По заданным условиям ищет ордера и закрывает/удаляет их. |//| Цена закрытия - Close на баре даты последнего пересчета ордера. |//| Сначала закрываются профитные сделки, потом - все остальные. |//| Возвращаемые значения: нет |//| Параметры: см. описание IsOrderFor() |//| |//+------------------------------------------------------------------+void v.CloseAllOrders(string sy="", int op=-1, int mn=-1, datetime ot=0){ int i, total = v.OrdersTotal(); if (total<=0) return; int Ticket[]; total = v.CreateTicketArray(Ticket, sy, op, mn, ot); if (total<=0) return; //Заглушка string sym; double point; int spread; // Закрываем только профитные сделки for (i=0; i<total; i++) { if(v.OrderSelect(Ticket[i], SELECT_BY_TICKET) && who.selected == MODE_TRADES && v.OrderProfit()>0) { int ty=v.OrderType(); if(ty<2) { sym = v.OrderSymbol(); point = MarketInfo(sym, MODE_POINT); spread = MarketInfo(sym,MODE_SPREAD); aTrade.CurrentDT=GetDoublePropArray(PROP.LastRecalcDT); double p=iClose(v.OrderSymbol(),0,iBarShift(v.OrderSymbol(),0,GetDoublePropArray(PROP.LastRecalcDT))); if(ty==OP_BUY) v.OrderClose(Ticket[i], v.OrderLots(), p, 3 ); else if(ty==OP_SELL) v.OrderClose(Ticket[i], v.OrderLots(), p + point*spread, 3 ); } else v.OrderDelete(Ticket[i]); } } // ... а теперь все остальные for (i=0; i<total; i++) { if(v.OrderSelect(Ticket[i], SELECT_BY_TICKET) && who.selected == MODE_TRADES) { ty=v.OrderType(); if(ty<2) { sym = v.OrderSymbol(); point = MarketInfo(sym, MODE_POINT); spread = MarketInfo(sym,MODE_SPREAD); aTrade.CurrentDT=GetDoublePropArray(PROP.LastRecalcDT); p=iClose(v.OrderSymbol(),0,iBarShift(v.OrderSymbol(),0,GetDoublePropArray(PROP.LastRecalcDT))); if(ty==OP_BUY) v.OrderClose(Ticket[i], v.OrderLots(), p, 3); else if(ty==OP_SELL) v.OrderClose(Ticket[i], v.OrderLots(), p + point*spread, 3); } else v.OrderDelete(Ticket[i]); } } return; } //+----------------------------------------------------------------------------+//| Автор : Ким Игорь В. aka KimIV, http://www.kimiv.ru |//+----------------------------------------------------------------------------+//| Версия : 01.09.2005 |//| Описание : Возвращает наименование торговой операции |//+----------------------------------------------------------------------------+//| Параметры: |//| op - идентификатор торговой операции |//+----------------------------------------------------------------------------+string GetNameOP(int op) { switch (op) { case OP_BUY : return("Buy"); case OP_SELL : return("Sell"); case OP_BUYLIMIT : return("Buy Limit"); case OP_SELLLIMIT: return("Sell Limit"); case OP_BUYSTOP : return("Buy Stop"); case OP_SELLSTOP : return("Sell Stop"); default : return("Unknown Operation"); }} //+----------------------------------------------------------------------------+//| Автор : Ким Игорь В. aka KimIV, http://www.kimiv.ru |//+----------------------------------------------------------------------------+//| Версия : 01.09.2005 |//| Описание : Возвращает наименование таймфрейма |//+----------------------------------------------------------------------------+//| Параметры: |//| TimeFrame - таймфрейм (количество секунд) (0 - текущий ТФ) |//+----------------------------------------------------------------------------+string GetNameTF(int TimeFrame=0) { if (TimeFrame==0) TimeFrame=Period(); switch (TimeFrame) { case PERIOD_M1: return("M1"); case PERIOD_M5: return("M5"); case PERIOD_M15: return("M15"); case PERIOD_M30: return("M30"); case PERIOD_H1: return("H1"); case PERIOD_H4: return("H4"); case PERIOD_D1: return("Daily"); case PERIOD_W1: return("Weekly"); case PERIOD_MN1: return("Monthly"); default: return("UnknownPeriod"); }} //+----------------------------------------------------------------------------+//| Автор : Ким Игорь В. aka KimIV, http://www.kimiv.ru |//+----------------------------------------------------------------------------+//| Версия : 01.09.2005 |//| Описание : Вывод сообщения в коммент и в журнал |//+----------------------------------------------------------------------------+//| Параметры: |//| m - текст сообщения |//+----------------------------------------------------------------------------+void Message(string m) { Comment(m); if (StringLen(m)>0) Print(m); } //+----------------------------------------------------------------------------+//| Автор : Ким Игорь В. aka KimIV, http://www.kimiv.ru |//+----------------------------------------------------------------------------+//| Версия : 13.03.2008 |//| Описание : Установка ордера. |//+----------------------------------------------------------------------------+//| Параметры: |//| sy - наименование инструмента (NULL или "" - текущий символ) |//| op - операция |//| ll - лот |//| pp - цена |//| sl - уровень стоп |//| tp - уровень тейк |//| mn - Magic Number |//| ex - Срок истечения |//+----------------------------------------------------------------------------+int v.SetOrder(string sy, int op, double ll, double pp, double sl=0, double tp=0, int mn=0, datetime ex=0, string lsComm="") { datetime ot; double pa, pb, mp; int err, it, ticket, msl; if(lsComm=="") lsComm=WindowExpertName()+" "+GetNameTF(Period()); if (sy=="" || sy=="0") sy=Symbol(); msl=MarketInfo(sy, MODE_STOPLEVEL); int dg = MarketInfo(sy, MODE_DIGITS); pp=NormalizeDouble(pp, dg); sl=NormalizeDouble(sl, dg); tp=NormalizeDouble(tp, dg); if (ex>0 && ex<aTrade.CurrentDT) ex=0; ticket=v.OrderSend(sy, op, ll, pp, Slippage, sl, tp, lsComm, mn, ex,0); //Print(GetLastError()); if (ticket>0) { return(ticket); } return(0); } //+----------------------------------------------------------------------------+//| Автор : Ким Игорь В. aka KimIV, http://www.kimiv.ru |//+----------------------------------------------------------------------------+//| Версия : 28.11.2006 |//| Описание : Модификация одного предварительно выбранного ордера. |//+----------------------------------------------------------------------------+//| Параметры: |//| pp - цена установки ордера |//| sl - ценовой уровень стопа |//| tp - ценовой уровень тейка |//| od - Срок истечения |//| cl - цвет значка модификации |//+----------------------------------------------------------------------------+void v.ModifyOrder(double pp=-1, double sl=0, double tp=0, datetime od = 0, color cl=CLR_NONE) { bool fm; double op, pa, pb, os, ot; int dg=MarketInfo(OrderSymbol(), MODE_DIGITS), er, it; if (pp<=0) pp=v.OrderOpenPrice(); if (sl<0 ) sl=v.OrderStopLoss(); if (tp<0 ) tp=v.OrderTakeProfit(); pp=NormalizeDouble(pp, dg); sl=NormalizeDouble(sl, dg); tp=NormalizeDouble(tp, dg); op=NormalizeDouble(v.OrderOpenPrice() , dg); os=NormalizeDouble(v.OrderStopLoss() , dg); ot=NormalizeDouble(v.OrderTakeProfit(), dg); if(od==0) od=v.OrderExpiration(); if (pp!=op || sl!=os || tp!=ot) { RefreshRates(); fm=v.OrderModify(OrderTicket(), pp, sl, tp, od, cl); if (fm) { } }} //+------------------------------------------------------------------+//| Группа функций-эмуляторов Order*() => v.Order*() |//| По всем функциям с префиксом v. - см. справку по MQL4 |//+------------------------------------------------------------------+ int v.OrdersTotal( ) { return(ArrayRange(aTrade,0));}int v.OrdersHistoryTotal( ) { return(aHistory.cnt);}bool v.OrderSelect( int index, int select, int pool=MODE_TRADES) { who.selected=pool; aTrade.p=-1; aHistory.p=-1; int i = 0; if(select==SELECT_BY_POS) { if(pool==MODE_TRADES) { if(index>=0&&index<v.OrdersTotal()) {aTrade.p=index; return(true);} } else {//MODE_HISTORY if(index>=0&&index<v.OrdersHistoryTotal()) {aHistory.p=index; return(true);} } } else {//SELECT_BY_TICKET for(i=0;i<v.OrdersTotal();i++) if(NormalizeDouble(aTrade[i,0],0)==index) { who.selected=MODE_TRADES; aTrade.p=i; return(true); } for(i=0;i<v.OrdersHistoryTotal();i++) if(NormalizeDouble(aHistory[i,0],0)==index) { who.selected=MODE_HISTORY; aHistory.p=i; return(true); } } return(false); } int v.OrderSend( string symbol, int cmd, double volume, double price, int slippage, double stoploss, double takeprofit, string comment="", int magic=0, datetime expiration=0, color arrow_color=CLR_NONE) { int total=v.OrdersTotal(); int nt=NextTicket(); //datetime d1=IIF(aTrade.CurrentDT==0,TimeCurrent(),aTrade.CurrentDT); ArrayResize(aTrade,total+1); ArrayResize(aTrade.strings,total+1); aTrade.strings[total,PROP.Symbol]=symbol; aTrade.strings[total,PROP.Comment]=comment; aTrade[total,PROP.Ticket]=nt; aTrade[total,PROP.OpenDT]=aTrade.CurrentDT; aTrade[total,PROP.Type]=cmd; aTrade[total,PROP.Lots]=volume; aTrade[total,PROP.OpenPrice]=price; aTrade[total,PROP.SL]=stoploss; aTrade[total,PROP.TP]=takeprofit; aTrade[total,PROP.Magic]=magic; aTrade[total,PROP.ExpDT]=expiration; aTrade[total,PROP.LastRecalcDT]=aTrade.CurrentDT; //if(cmd==OP_BUY||cmd==OP_BUYSTOP||cmd==OP_BUYLIMIT) { //aTrade[total,PROP.MaxDD]=price; //aTrade[total,PROP.MaxProfit]=price; } //aTrade.CurrentDT=0; _Print("Array send "+nt); return(nt); } bool v.OrderClose( int ticket, double lots, double price, int slippage, color Color=CLR_NONE){ _Print("Closing "+ticket); double point = MarketInfo(v.OrderSymbol(), MODE_POINT); if(v.OrderSelect(ticket,SELECT_BY_TICKET) && who.selected == MODE_TRADES) { SetDoublePropArray(PROP.CloseDT,aTrade.CurrentDT); //aTrade.CurrentDT=0; SetDoublePropArray(PROP.ClosePrice, price); int ty=v.OrderType(); if(ty==OP_BUY) { SetDoublePropArray(PROP.Profit, CalcOrderProfit(price, aTrade.CurrentDT));//(price-v.OrderOpenPrice())/point); } else if(ty==OP_SELL) { SetDoublePropArray(PROP.Profit, CalcOrderProfit(price, aTrade.CurrentDT));//(-price+v.OrderOpenPrice())/point); } else { v.OrderDelete( ticket ); return(true); } //SetDoublePropArray(PROP.Profit, price); int newsize=v.OrdersHistoryTotal()+1; ArrayResize_aHistory(newsize); ArrayCopy(aHistory,aTrade,(newsize-1)*MAX_FIELDS,aTrade.p*MAX_FIELDS,MAX_FIELDS); ArrayCopy(aHistory.strings,aTrade.strings,(newsize-1)*2,aTrade.p*2,2); if(aTrade.CalcBalance) { double AB = v.OrderProfit(); if(newsize>1) AB += aHistory[newsize-2][PROP.AccBalance]; aHistory[newsize-1][PROP.AccBalance] = AB; v.OrderDelete( ticket ); aHistory[newsize-1][PROP.AccEquity] = v.AccountEquity(); } else { v.OrderDelete( ticket ); } return(true); } else return(false); } bool v.OrderDelete( int ticket, color arrow_color=CLR_NONE) { if(v.OrderSelect(ticket,SELECT_BY_TICKET) && who.selected == MODE_TRADES) { SetDoublePropArray(PROP.CloseDT,aTrade.CurrentDT); double a[][MAX_FIELDS]; string as[][2]; int oldsize=v.OrdersTotal(); int newsize=oldsize-1; ArrayResize(a, newsize); ArrayResize(as, newsize); if(newsize==0) { ArrayResize(aTrade,newsize); ArrayResize(aTrade.strings,newsize); aTrade.p=-1; return(true); } if(aTrade.p==0) { ArrayCopy(a,aTrade,0,1*MAX_FIELDS,newsize*MAX_FIELDS); ArrayCopy(as,aTrade.strings,0,1*2,newsize*2); } else if(aTrade.p==newsize) { ArrayCopy(a,aTrade,0,0,newsize*MAX_FIELDS); ArrayCopy(as,aTrade.strings,0,0,newsize*2); } else { ArrayCopy(a,aTrade,0,0,aTrade.p*MAX_FIELDS); ArrayCopy(as,aTrade.strings,0,0,aTrade.p*2); ArrayCopy(a,aTrade,aTrade.p*MAX_FIELDS,(aTrade.p+1)*MAX_FIELDS,(newsize-aTrade.p)*MAX_FIELDS); ArrayCopy(as,aTrade.strings,aTrade.p*2,(aTrade.p+1)*2,(newsize-aTrade.p)*2); } ArrayResize(aTrade,newsize); ArrayResize(aTrade.strings,newsize); ArrayCopy(aTrade,a); ArrayCopy(aTrade.strings,as); aTrade.p=-1; return(true); } else return(false); } bool v.OrderModify( int ticket, double price, double stoploss, double takeprofit, datetime expiration, color arrow_color=CLR_NONE) {}int v.OrderTicket( ) { return(GetDoublePropArray(PROP.Ticket));}datetime v.OrderOpenTime( ) { return(GetDoublePropArray(PROP.OpenDT));}int v.OrderType( ) { return(GetDoublePropArray(PROP.Type));}double v.OrderLots( ) { return(GetDoublePropArray(PROP.Lots));}double v.OrderOpenPrice( ) { return(GetDoublePropArray(PROP.OpenPrice));}double v.OrderStopLoss( ) { return(GetDoublePropArray(PROP.SL));}double v.OrderTakeProfit( ) { return(GetDoublePropArray(PROP.TP));}int v.OrderMagicNumber( ) { return(GetDoublePropArray(PROP.Magic));}datetime v.OrderExpiration( ) { return(GetDoublePropArray(PROP.ExpDT));}double v.OrderClosePrice( ) { return(GetDoublePropArray(PROP.ClosePrice));}datetime v.OrderCloseTime( ) { return(GetDoublePropArray(PROP.CloseDT));}double v.OrderProfit( ) { return(GetDoublePropArray(PROP.Profit));}string v.OrderSymbol( ) { return(GetStringPropArray(PROP.Symbol));}string v.OrderComment( ) { return(GetStringPropArray(PROP.Comment));} double v.AccountBalance( ){ double ret = 0; if(aTrade.CalcBalance && aHistory.cnt>0) ret = aHistory[aHistory.cnt-1][PROP.AccBalance]; return (ret); } double v.AccountEquity( ){ double ret = v.AccountBalance(); if(aTrade.CalcBalance && aTrade.cnt>0) for(int i = 0; i<v.OrdersTotal();i++) if(v.OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) ret += v.OrderProfit(); return (ret); } //+------------------------------------------------------------------+//| Группа служебных функций. |//+------------------------------------------------------------------+ //+------------------------------------------------------------------+//| Включает/выключает режим расчета баланса и эквити. |//| Возвращает значение флага до вызова метода. |//| |//+------------------------------------------------------------------+bool CalcBalance(bool newval){ bool old = aTrade.CalcBalance; aTrade.CalcBalance = newval; return(old); } //+------------------------------------------------------------------+//| Для увеличения быстродействия при работе с большим количеством |//| ордеров массив для хранения OrdersHistory увеличиваем по 100 |//| элементов за раз. |//| |//+------------------------------------------------------------------+void ArrayResize_aHistory(int newsize){ int size=ArrayRange(aHistory,0); bool need=false; while(newsize>size) { size+=100; need=true; } if(need) { ArrayResize(aHistory,newsize); ArrayResize(aHistory.strings,newsize); } aHistory.cnt=newsize; } //+------------------------------------------------------------------+//| Генератор уникальных номеров ордеров. |//| |//+------------------------------------------------------------------+int NextTicket(){ next_t++; return(next_t); } //+------------------------------------------------------------------+//| Возращает значение указанного параметра выбранного ордера. |//| |//+------------------------------------------------------------------+double GetDoublePropArray( int col){ if(who.selected==MODE_TRADES && aTrade.p>=0) return(aTrade[aTrade.p,col]); if(who.selected==MODE_HISTORY && aHistory.p>=0) return(aHistory[aHistory.p,col]); return(-1); } string GetStringPropArray( int col){ //Print(aTrade.p); if(who.selected==MODE_TRADES && aTrade.p>=0) return(aTrade.strings[aTrade.p,col]); if(who.selected==MODE_HISTORY && aHistory.p>=0) return(aHistory.strings[aHistory.p,col]); return("err"); } //+------------------------------------------------------------------+//| Устанавливает значение указанного параметра выбранного ордера. |//| |//+------------------------------------------------------------------+bool SetDoublePropArray( int col, double d){ //_Print(StringConcatenate(who.selected,p,aTrade.p)); if(who.selected==MODE_TRADES && aTrade.p>=0) { aTrade[aTrade.p,col]=d; return(true); } return(false); } bool SetStringPropArray( int col, string s){ if(who.selected==MODE_TRADES && aTrade.p>=0) { aTrade.strings[aTrade.p,col]=s; return(true); } return(false); } //+------------------------------------------------------------------+//| Устанавливает "текущее время" для эмуляции сделок. |//| Вызывается в основном коде, например на каждом новом баре. |//+------------------------------------------------------------------+void SetCurrentDateTime(datetime dt){ aTrade.CurrentDT = dt; } //+------------------------------------------------------------------+//| Пересчитывает массив открытых ордеров . |//| Вызывается в основном коде, например на каждом новом баре. |//| Параметр: номер бара, на котором пересчет прекращается. |//| |//+------------------------------------------------------------------+void RecalcTradeArray(datetime dt=0){ int Ticket[]; int K=v.CreateTicketArray(Ticket); //_Print("trades = "+K); for (int i=0;i<K;i++) { if(v.OrderSelect(Ticket[i],SELECT_BY_TICKET)) RecalcOrder(dt); } } //+------------------------------------------------------------------+//| Пересчитывает выбранный ордер. |//| Параметр: номер бара, на котором пересчет прекращается. У каждого|//| ордера есть служебный параметр - дата последнего пересчета. Для |//| выбранного ордера последовательно обсчитываются все бары от бара |//| последнего пересчета до бара указанного в параметре. При пересче-| //| проверяются условия на открытие отложенных, закрытие открытых по |//| SL и TP, истечение срока жизни (работает в т.ч. и для уже откры- |//| тых позиций, не только отложенников). Вычисляются максимальные |//| просадка и возможная прибыль за время жизни позиции |//| |//+------------------------------------------------------------------+bool RecalcOrder(datetime dt=0){ string sy=v.OrderSymbol( ); double point = MarketInfo(sy, MODE_POINT); int spread = MarketInfo(sy,MODE_SPREAD); int dg = MarketInfo(sy,MODE_DIGITS); double sp = NormalizeDouble(spread*point,dg); int ty=v.OrderType(); int s0=iBarShift(sy,0,GetDoublePropArray(PROP.LastRecalcDT)); int sh=0; if(dt>0) sh=iBarShift(sy,0,dt,true); if(sh<0) return; _Print("Recalc "+v.OrderTicket()+" "+sy+" "+s0); for(int i=s0;i>=sh;i--) { double high = NormalizeDouble( iHigh(sy,0,i), dg), low = NormalizeDouble( iLow(sy,0,i), dg), close = NormalizeDouble(iClose(sy,0,i), dg); double op=GetDoublePropArray(PROP.OpenPrice); double sl=GetDoublePropArray(PROP.SL); double tp=GetDoublePropArray(PROP.TP); datetime curdt = iTime(sy,0,i); bool res=SetDoublePropArray(PROP.LastRecalcDT, curdt); datetime exp=GetDoublePropArray(PROP.ExpDT); aTrade.CurrentDT=curdt; _Print("last recalc "+res); if((ty==OP_BUYSTOP||ty==OP_BUYLIMIT) && op>=low+sp && op<=high+sp) { SetDoublePropArray(PROP.OpenDT,curdt); ty=OP_BUY; SetDoublePropArray(PROP.Type,ty); } if(ty==OP_BUY) { SetDoublePropArray(PROP.Profit,CalcOrderProfit(close, aTrade.CurrentDT)); //if(sl==0) SetDoublePropArray(PROP.MaxDD,MathMin(GetDoublePropArray(PROP.MaxDD),(low-op)/point)); //if(tp==0) SetDoublePropArray(PROP.MaxProfit,MathMax(GetDoublePropArray(PROP.MaxProfit),(high-op)/point)); if(sl>0 && sl>=low) {v.OrderClose(GetDoublePropArray(PROP.Ticket),v.OrderLots(),sl,2); break;} else if(tp>0 && tp<=high) {v.OrderClose(GetDoublePropArray(PROP.Ticket),v.OrderLots(),tp,2); break;} } if((ty==OP_SELLSTOP||ty==OP_SELLLIMIT) && op>=low && op<=high) { SetDoublePropArray(PROP.OpenDT,curdt); ty=OP_SELL; SetDoublePropArray(PROP.Type,ty); } if(ty==OP_SELL) { SetDoublePropArray(PROP.Profit,CalcOrderProfit((close+sp), aTrade.CurrentDT)); //if(sl==0) SetDoublePropArray(PROP.MaxDD,MathMin(GetDoublePropArray(PROP.MaxDD),(op-(high+sp))/point)); //if(tp==0) SetDoublePropArray(PROP.MaxProfit,MathMax(GetDoublePropArray(PROP.MaxProfit),(op-(low+sp))/point)); if(sl>0 && sl<=high+sp) {v.OrderClose(GetDoublePropArray(PROP.Ticket),v.OrderLots(),sl,2); break;} else if(tp>0 && tp>=low+sp) {v.OrderClose(GetDoublePropArray(PROP.Ticket),v.OrderLots(),tp,2); break;} } if(exp>0 && exp<=aTrade.CurrentDT) {v.OrderClose(GetDoublePropArray(PROP.Ticket),v.OrderLots(),close,2); break;} } return(true); } //+------------------------------------------------------------------+//| Вычисляет стоимость сделки в валюте депозита |//| Параметры: |//| price текущая цена для расчета |//| dt опорная дата/время для расчета кросс-курса |//| |//+------------------------------------------------------------------+ double CalcOrderProfit(double price, datetime dt){ string sy = v.OrderSymbol(); double lots = v.OrderLots(); int op = v.OrderType(); double LS = MarketInfo(sy, MODE_LOTSIZE); double OrdProf = lots * LS * (price - v.OrderOpenPrice()) * IIF(op==OP_BUY,1,-1); string FirstPart = StringSubstr(sy, 0, 3); string SecondPart = StringSubstr(sy, 3, 3); string DepoCurr = AccountCurrency(); if( SecondPart == DepoCurr ) { /**/ } else if( FirstPart == DepoCurr ) {OrdProf /= price;} else { if(MarketInfo( DepoCurr + SecondPart, MODE_BID ) > 0) sy = DepoCurr + SecondPart; else sy = SecondPart + DepoCurr; int sh = iBarShift(sy, 0, dt, true); if(sh < 0) { sh = iBarShift(sy, 0, dt, false); Print("Error! No history for "+sy+" at "+TimeToStr(dt)+". Trying at "+TimeToStr(iTime(sy,0,sh))); price=iClose(sy, 0, sh); //return(-1); } else { price=iClose(sy, 0, sh); } FirstPart = StringSubstr(sy, 0, 3); SecondPart = StringSubstr(sy, 3, 3); if( SecondPart == DepoCurr ) OrdProf *= price; else if( FirstPart == DepoCurr ) OrdProf /= price; } OrdProf = NormalizeDouble(OrdProf, 2) ; return(OrdProf); } //+------------------------------------------------------------------+//| Сохраняет массивы ордеров в бинарном формате. |//| Параметр: имя группы служебных файлов. |//| На выходе 4 файла: |//| "bin."+fn+".hist" |//| "bin."+fn+".histstring" |//| "bin."+fn+".trade" |//| "bin."+fn+".tradestring" |//| Может применяться для промежуточного сохранения результатов, а |//| также для сохранения результатов между сеансами. | //| |//+------------------------------------------------------------------+void SaveArrays(string fn){ int h=FileOpen("bin."+fn+".hist",FILE_WRITE|FILE_BIN); FileWriteArray(h,aHistory,0,ArraySize(aHistory)); FileClose(h); h=FileOpen("bin."+fn+".histstring",FILE_WRITE|FILE_BIN); FileWriteArray(h,aHistory.strings,0,ArraySize(aHistory.strings)); FileClose(h); h=FileOpen("bin."+fn+".trade",FILE_WRITE|FILE_BIN); FileWriteArray(h,aTrade,0,ArraySize(aTrade)); FileClose(h); h=FileOpen("bin."+fn+".tradestring",FILE_WRITE|FILE_BIN); FileWriteArray(h,aTrade.strings,0,ArraySize(aTrade.strings)); FileClose(h); } //+------------------------------------------------------------------+//| Загружает массивы ордеров из бинарных файлов |//| Параметр: имя группы служебных файлов. |//| На входе 4 файла: |//| "bin."+fn+".hist" |//| "bin."+fn+".histstring" |//| "bin."+fn+".trade" |//| "bin."+fn+".tradestring" |//| |//+------------------------------------------------------------------+void LoadArrays(string fn){ int h=FileOpen("bin."+fn+".hist",FILE_READ|FILE_BIN); int h1=FileOpen("bin."+fn+".histstring",FILE_READ|FILE_BIN); double a[MAX_FIELDS]; int k=v.OrdersHistoryTotal(); while((!FileIsEnding(h))&&(!FileIsEnding(h))) { ArrayResize(aHistory,(k+1)); ArrayResize(aHistory.strings,(k+1)); FileReadArray(h,aHistory,k*MAX_FIELDS,MAX_FIELDS); FileReadArray(h1,aHistory.strings,k*2,2); aHistory.cnt++; k++; } if(k>0) { aHistory.cnt--; ArrayResize(aHistory,(k-1)); ArrayResize(aHistory.strings,(k-1)); } FileClose(h); FileClose(h1); h=FileOpen("bin."+fn+".trade",FILE_READ|FILE_BIN); h1=FileOpen("bin."+fn+".tradestring",FILE_READ|FILE_BIN); k=v.OrdersTotal(); while((!FileIsEnding(h))&&(!FileIsEnding(h))) { ArrayResize(aTrade,(k+1)); ArrayResize(aTrade.strings,(k+1)); FileReadArray(h,aTrade,k*MAX_FIELDS,MAX_FIELDS); FileReadArray(h1,aTrade.strings,k*2,2); k++; } if(k>0) { ArrayResize(aTrade,(k-1)); ArrayResize(aTrade.strings,(k-1)); } FileClose(h); FileClose(h1); for(k=0;k<v.OrdersHistoryTotal();k++) next_t=MathMax(next_t,aHistory[k,0]); for(k=0;k<v.OrdersTotal();k++) next_t=MathMax(next_t,aTrade[k,0]); } //+------------------------------------------------------------------+//| Выводит массивы ордеров в читабельном формате |//| Параметр: имя группы служебных файлов. |//| На выходе 2 файла: |//| "deb."+fn+".hist.csv" |//| "deb."+fn+".trade.csv" |//| применяется для контроля работы, а также для дальнейшего анализа |//| сделок, например, в Excel |//| |//+------------------------------------------------------------------+void DebugPrintArrays(string fn){ string s="", p=""; int i,j; int h=FileOpen("deb."+fn+".hist.csv",FILE_WRITE|FILE_CSV,csv.dem); FileWrite(h,"Ticket","OpenDT","Type","Lots","OpenPrice","SL","TP","Magic","ExpDT","ClosePrice","CloseDT", "Profit","LastRecalcDT","AccBalance","AccEquity","MaxDD","MaxProfit","Symbol","Comment"); for(i=0;i<v.OrdersHistoryTotal();i++) { s=""; for(j=0;j<MAX_FIELDS;j++) { if(j==PROP.OpenDT||j==PROP.ExpDT||j==PROP.CloseDT||j==PROP.LastRecalcDT) p=TimeToStr(aHistory[i,j],TIME_DATE|TIME_MINUTES|TIME_SECONDS); else if(j==PROP.Ticket||j==PROP.Type||j==PROP.Magic) p=DoubleToStr(aHistory[i,j],0); else p=DoubleToStr(aHistory[i,j],4); s=s+p+csv.dem; } s=s+aHistory.strings[i,0]+csv.dem+aHistory.strings[i,1]; FileWrite(h,s); } FileClose(h); h=FileOpen("deb."+fn+".trade.csv",FILE_WRITE|FILE_CSV,csv.dem); FileWrite(h,"Ticket","OpenDT","Type","Lots","OpenPrice","SL","TP","Magic","ExpDT","ClosePrice","CloseDT", "Profit","LastRecalcDT","AccBalance","AccEquity","MaxDD","MaxProfit","Symbol","Comment"); datetime d=0; for(i=0;i<v.OrdersTotal();i++) { s=""; for(j=0;j<MAX_FIELDS;j++) { if(j==PROP.OpenDT||j==PROP.ExpDT||j==PROP.CloseDT||j==PROP.LastRecalcDT) p=TimeToStr(aTrade[i,j],TIME_DATE|TIME_MINUTES|TIME_SECONDS); else if(j==PROP.Ticket||j==PROP.Type||j==PROP.Magic) p=DoubleToStr(aTrade[i,j],0); else p=DoubleToStr(aTrade[i,j],4); s=s+p+csv.dem; } s=s+aTrade.strings[i,0]+csv.dem+aTrade.strings[i,1]; FileWrite(h,s); } FileClose(h); } //+------------------------------------------------------------------+//| Вывод отладочной информации в лог-файл |//| Параметр: строка для записи в файл |//| |//+------------------------------------------------------------------+void _Print(string s){/* int fh=FileOpen("vo.log",FILE_WRITE|FILE_READ); FileSeek(fh, 0, SEEK_END); FileWrite(fh,TimeToStr(TimeCurrent())," ",s); FileClose(fh);*/} //*************************************** // string sIIF(bool cr, string r1, string r2){ if(cr) return(r1); else return(r2); } double IIF(bool cr, double r1, double r2){ if(cr) return(r1); else return(r2); } // //***************************************