Virtual Trade
//+------------------------------------------------------------------+
//| VirtualTrend.mqh |
//| Copyright © Evgeniy Trofimov, 2010 |
//| http://forum.mql4.com/ru/16793/ |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| V I R T U A L T R E N D |
//| Copyright: Evgeniy Trofimov, 2010 |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
// This library contains the following functions:
//Main:
// + VirtualSend
// + VirtualSelect
// + VirtualClose - cancels pending orders and closes positions
// + VirtualModify
//Auxiliary:
// + VirtualCopyPosition - copies position into the other region of array
// + VirtualHighTicket - searches for a young ticket
// + VirtualFileLoad - loads array of trades from a file
// + VirtualFileSave - saves array of trades to a file
// + VirtualUpdate - updates information from market
// + VirtualFilter - creates list of indexes the of array of found positions
// + VirtualProfitHistory - calculates value of moving average of balance
// + VirtualProfit - calculates value of profit of open position at the current moment
// + VirtualRating - calculates rating of profitable TS in percentage terms
// + VirtualExist - this function is used for restricting of opening 2 trades in succession by a single signal
//+------------------------------------------------------------------+
extern bool RatingON=true; // - switch of rating (if it is disable, trades in the file must comply with real trading)
extern bool FastTest=true; // - don't create the file while testing
#define VIRT_TRADES 1 // - trade orders and positions
#define VIRT_HISTORY 0 // - closed positions and canceled pending orders
int Virt.Count; // - number of positions in array (from 0 to 999)
int Virt.Index; // - position of selected trade in the base of functions VirtualSelect()
int VirtBufferSize = 16; // - number of elements in one line of the base (next lines)
int Virt.Ticket[1000]; // - Number of order
datetime Virt.OpenTime[1000]; // - Time of opening
int Virt.Type[1000]; // - Type of trade
double Virt.Lots[1000]; // - Volume
string Virt.Symbol[1000]; // - Symbol
double Virt.OpenPrice[1000]; // - Open price
double Virt.StopLoss[1000];
double Virt.TakeProfit[1000];
datetime Virt.CloseTime[1000]; // - Tim of closing
double Virt.ClosePrice[1000]; // - Close price
double Virt.Swap[1000]; // - Swap
double Virt.Profit[1000]; // - Profit in pipslots
string Virt.Comment[1000]; // - Comments
int Virt.MagicNumber[1000]; // - Magic number
datetime Virt.Expiration[1000]; // - Date of canceling a pending order
int Virt.Status[1000]; // - Status of order: 1 - open position/pending order; 0 - closed position/canceled order
int Virt.Filter[1000];
int Virt.Filter.Count;
int Err.Number; // - Error number
string Err.Description; // - Description of last
//+------------------------------------------------------------------+
double VirtualRating(int fMagic, string fSymbol, int period, int applied_price, string filename="virtual.csv"){
//The function returns rating of positive trades
//created by one or another trading strategy
//at a certain symbol (100% is most profitable TS, 0% - neither fish, nor fowl)
//fMagic - magic number, which is used for telling one trading system from another
//fSymbol - symbol, the rating is considered for
//period - number of last trades
//applied_price - Price used: 0 - in the deposit currency, 1 - in points;
//filename - file of trades
if(!RatingON) return(100);
int MagicNum[];
double Profit[];
//double Rating[];
int i, j;
bool MagicExist;
VirtualFileLoad(filename);
if(VirtualFilter(VIRT_HISTORY, -1, -1, fSymbol)<1) return (0);
for(i=0; i<Virt.Filter.Count; i++){
MagicExist=false;
for(j=0; j<ArraySize(MagicNum); j++){
if(MagicNum[j]==Virt.MagicNumber[Virt.Filter[i]]){
MagicExist=true;
break;
}
}//Next j
if(!MagicExist){
ArrayResize(MagicNum, ArraySize(MagicNum)+1);
MagicNum[ArraySize(MagicNum)-1]=Virt.MagicNumber[Virt.Filter[i]];
}
}//Next i
ArrayResize(Profit, ArraySize(MagicNum));
for(i=0; i<ArraySize(MagicNum); i++){
Profit[i]=VirtualProfitHistory(applied_price, period, 0, -1, -1, fSymbol, MagicNum[i], true)+
VirtualProfit( applied_price, -1, -1, fSymbol, MagicNum[i], true);
if(Profit[i]<0) Profit[i]=0;
}//Next i
j=ArrayMaximum(Profit); // 100%
if(Profit[j]==0) return (0);
//ArrayResize(Rating, ArraySize(MagicNum));
for(i=0; i<ArraySize(MagicNum); i++){
if(fMagic==MagicNum[i]){
return(100*Profit[i]/Profit[j]);
}
}//Next i
return(0);
}//VirtualRating()
//+------------------------------------------------------------------+
double VirtualProfit(int applied_price=1, int fTicket=-1, int fType=-1, string fSymbol="", int fMagic=-1, bool dh = false, string fComment=""){
//The function returns value of profit of open positions
//applied_price - Price used: 0 - in the deposit currency, 1 - in points;
//dh = true - Divide by the number of days to calculate the relative profit
//Other parameters correspond to the ones of the VirtualFilter() function
//Note: file with positions should be loaded to call this function.
double Profit, plus, deltaDay;
datetime OldDay = TimeCurrent();
if(VirtualFilter(VIRT_TRADES, fTicket, fType, fSymbol, fMagic, fComment)>0){
for(int i=0; i<Virt.Filter.Count; i++){
if(Virt.Type[Virt.Filter[i]]<2){
if(Virt.OpenTime[Virt.Filter[i]]<OldDay) OldDay=Virt.OpenTime[Virt.Filter[i]];
if(applied_price==0){//In the deposit currency
plus=Virt.Profit[Virt.Filter[i]];
}else{//In points
if(Virt.Type[Virt.Filter[i]]==OP_BUY){
plus=(Virt.ClosePrice[Virt.Filter[i]]-Virt.OpenPrice[Virt.Filter[i]])/MarketInfo(Virt.Symbol[Virt.Filter[i]],MODE_POINT);
}else{
plus=(Virt.OpenPrice[Virt.Filter[i]]-Virt.ClosePrice[Virt.Filter[i]])/MarketInfo(Virt.Symbol[Virt.Filter[i]],MODE_POINT);
}
}
Profit=Profit+plus;
}
}//Next i
}
if(dh){
deltaDay=(TimeCurrent()-OldDay)/(24*60*60);
if(deltaDay<1){
deltaDay=1;
}
Profit=Profit/deltaDay;
}
return(Profit);
}//VirtualProfit()
//+------------------------------------------------------------------+
double VirtualProfitHistory(int applied_price=1, int period=0, int shift=0,
int fTicket=-1, int fType=-1, string fSymbol="", int fMagic=-1, bool dh = false, string fComment=""){
//The function returns value of profit of closed trades
//applied_price - Price used: 0 - in the deposit currency, 1 - in points;
//period - Period of averaging for calculation of profit. If it is equal to 0, then for all the trades;
//shift - Index of obtained value from the array of trades (shift back relatively to the last closed trade on the specified number of trades).
//dh = true - Divide by the number of days to calculate the relative profit
//Other parameters correspond to the ones of the VirtualFilter() function
//Note: file with positions should be loaded to call this function.
double Profit, plus, deltaDay;
datetime beginDay=TimeCurrent(), endDay;
int j, k;
if(VirtualFilter(VIRT_HISTORY, fTicket, fType, fSymbol, fMagic, fComment)>0){
for(int i=Virt.Filter.Count-1; i>=0; i--){
if(Virt.Type[Virt.Filter[i]]<2){
k++;
if(k>shift){
j++;
if(j>period && period>0) break;
if(Virt.OpenTime[Virt.Filter[i]]<beginDay) beginDay=Virt.OpenTime[Virt.Filter[i]];
if(Virt.CloseTime[Virt.Filter[i]]>endDay) endDay=Virt.CloseTime[Virt.Filter[i]];
if(applied_price==0){//In the deposit currency
plus=Virt.Profit[Virt.Filter[i]];
}else{//In points
if(Virt.Type[Virt.Filter[i]]==OP_BUY){
plus=(Virt.ClosePrice[Virt.Filter[i]]-Virt.OpenPrice[Virt.Filter[i]])/MarketInfo(Virt.Symbol[Virt.Filter[i]],MODE_POINT);
}else{
plus=(Virt.OpenPrice[Virt.Filter[i]]-Virt.ClosePrice[Virt.Filter[i]])/MarketInfo(Virt.Symbol[Virt.Filter[i]],MODE_POINT);
}
}
Profit=Profit+plus;
}
}
}//Next i
}
if(dh){
deltaDay=(endDay-beginDay)/(24*60*60);
//Print(TimeToStr(endDay)+" - "+TimeToStr(beginDay)+" = "+DoubleToStr(deltaDay,2)+" äíåé");
if(deltaDay<1){
deltaDay=1;
}
Profit=Profit/deltaDay;
}
return(Profit);
}//VirtualProfitHistory()
//+------------------------------------------------------------------+
bool VirtualSelect(int index, int select, int pool=VIRT_TRADES){
//The function chooses an order for further working with it. Returns TRUE if the function is executed successfully.
//index - Position of order or number of order depending on the second parameter.
//select - Flag of mode of choosing. Can have one of the following values:
//SELECT_BY_POS - the index number of position in the list is passed in the index parameter,
//SELECT_BY_TICKET - the number of ticket is passed in the index parameter.
//pool - Data source for choosing. Used when the select parameter is equal to SELECT_BY_POS. Can have one of the following values:
//VIRT_TRADES (default) - order is chosen from open and pending orders,
//VIRT_HISTORY - order is chosen from closed and deleted orders
//Note: file with positions should be loaded to call this function.
if(select==SELECT_BY_POS){
if(VirtualFilter(pool)>0){
if(index<Virt.Filter.Count){
Virt.Index=Virt.Filter[index];
return(true);
}
}
}else{ //select==SELECT_BY_TICKET
if(VirtualFilter(-1,index)>0){
Virt.Index=Virt.Filter[0];
return(true);
}
}
return(false);
}//VirtualSelect()
//+------------------------------------------------------------------+
bool VirtualModify(int ticket, double price, double stoploss, double takeprofit, datetime expiration, string filename="virtual.csv"){
//Changes parameters of previously opened positions and pending orders. Returns TRUE if the function is executed successfully.
//Attention!!! There are no checks for the minimum acceptable level of 'price', SL and TP!!!
int i;
VirtualFileLoad(filename);
if(VirtualFilter(VIRT_TRADES, ticket)>0){
i=Virt.Filter[0];
if(Virt.Type[i]<2){
if(stoploss>0) Virt.StopLoss[i]=stoploss;
if(takeprofit>0) Virt.TakeProfit[i]=takeprofit;
}else{
if(price>0) Virt.OpenPrice[i]=price;
if(stoploss>0) Virt.StopLoss[i]=stoploss;
if(takeprofit>0) Virt.TakeProfit[i]=takeprofit;
if(expiration>0) Virt.Expiration[i]=expiration;
}
VirtualFileSave(filename);
return(true);
} else {
Err.Number = 102;
Err.Description = "Number of position couldn't be found at the attempt to change it";
return(false);
}
}//VirtualModify()
//+------------------------------------------------------------------+
bool VirtualClose(int ticket, string filename="virtual.csv"){
//Closing position. Returns TRUE if the function is executed successfully. Returns FALSE if the function is function execution failed.
//Information about errors is stored in the Err.* variables
int i, j;
VirtualFileLoad(filename);
if(VirtualFilter(VIRT_TRADES, ticket)>0){
i=Virt.Filter[0];
if(Virt.Type[i]==OP_BUY){
Virt.CloseTime[i]=TimeCurrent(); // - Time of closing
Virt.ClosePrice[i]=MarketInfo(Virt.Symbol[i], MODE_BID); // - Price of closing
Virt.Swap[i]=MathRound((Virt.CloseTime[i]-Virt.OpenTime[i])/(24*60*60))*MarketInfo(Virt.Symbol[i], MODE_SWAPLONG)*Virt.Lots[i];
Virt.Profit[i]=(Virt.ClosePrice[i]-Virt.OpenPrice[i])*Virt.Lots[i]*MarketInfo(Virt.Symbol[i],MODE_TICKVALUE)/MarketInfo(Virt.Symbol[i], MODE_POINT)+Virt.Swap[i];
}else if(Virt.Type[i]==OP_SELL){
Virt.CloseTime[i]=TimeCurrent(); // - Time of closing
Virt.ClosePrice[i]=MarketInfo(Virt.Symbol[i], MODE_ASK); // - Price of closing
Virt.Swap[i]=MathRound((Virt.CloseTime[i]-Virt.OpenTime[i])/(24*60*60))*MarketInfo(Virt.Symbol[i], MODE_SWAPSHORT)*Virt.Lots[i];
Virt.Profit[i]=(Virt.OpenPrice[i]-Virt.ClosePrice[i])*Virt.Lots[i]*MarketInfo(Virt.Symbol[i],MODE_TICKVALUE)/MarketInfo(Virt.Symbol[i], MODE_POINT)+Virt.Swap[i];
}else if(Virt.Type[i]>1 && Virt.Type[i]<6){
Virt.CloseTime[i]=TimeCurrent(); // - Time of canceling
Virt.Comment[i]=Virt.Comment[i]+"[canceled]";
}
for(j=i-1; j>=0; j--){
if(Virt.Status[j]==0) break;
}//Next j
Virt.Status[i]=0;
if(j<i-1){
j=j+1;
VirtualCopyPosition(j, 999);
VirtualCopyPosition(i, j);
VirtualCopyPosition(999, i);
}
VirtualFileSave(filename);
return(true);
} else {
Err.Number = 101;
Err.Description = "Number of positions couldn't be found at the attempt to close it";
return(false);
}
}//VirtualClose()
//+------------------------------------------------------------------+
int VirtualFilter(int fStatus=-1, int fTicket=-1, int fType=-1, string fSymbol="", int fMagic=-1, string fComment=""){
//The function creates the list of indexes of the array of positions found
//according to the existing parameters of filter;
//and returns size of the list
//Note: file with positions should be loaded to call this function.
Virt.Filter.Count=0;
for(int i = 0; i<Virt.Count; i++){
if(fTicket==-1 || Virt.Ticket[i]==fTicket){
if(fType==-1 || Virt.Type[i]==fType){
if(fSymbol=="" || Virt.Symbol[i]==fSymbol) {
if(fComment=="" || StringFind(Virt.Comment[i], fComment)>-1) {
if(fMagic==-1 || Virt.MagicNumber[i]==fMagic) {
if(fStatus==-1 || Virt.Status[i]==fStatus) {
Virt.Filter[Virt.Filter.Count]=i;
Virt.Filter.Count++;
}
}
}
}
}
}
}//Next i
return(Virt.Filter.Count);
}//VirtualFilter()
//+------------------------------------------------------------------+
void VirtualUpdate(string filename="virtual.csv"){
//Procedure of updating the file of trades in accordance with the market changes.
//The following actions are performed here:
// + charging of swaps;
// + virtual closing of trades by preliminary set StopLoss and TakeProfit
// + updating of close price of open positions, calculating profit;
// + opening pending orders;
// + expiration of pending orders that haven't triggered;
bool is_changed, is_closed;
int i, j;
VirtualFileLoad(filename);
for(i=Virt.Count-1; i>=0; i--){
is_closed=false;
if(Virt.Status[i]==1) {
is_changed=true;
switch(Virt.Type[i]){
case OP_BUY:
Virt.CloseTime[i]=TimeCurrent(); // - Time of closing
Virt.ClosePrice[i]=MarketInfo(Virt.Symbol[i], MODE_BID); // - Price of closing
Virt.Swap[i]=MathRound((Virt.CloseTime[i]-Virt.OpenTime[i])/(24*60*60))*MarketInfo(Virt.Symbol[i], MODE_SWAPLONG)*Virt.Lots[i];
Virt.Profit[i]=(Virt.ClosePrice[i]-Virt.OpenPrice[i])*Virt.Lots[i]*MarketInfo(Virt.Symbol[i],MODE_TICKVALUE)/MarketInfo(Virt.Symbol[i], MODE_POINT)+Virt.Swap[i];
if(Virt.TakeProfit[i]>0){
if(MarketInfo(Virt.Symbol[i], MODE_BID)>=Virt.TakeProfit[i]){
Virt.ClosePrice[i]=Virt.TakeProfit[i]; // - Close price
Virt.Profit[i]=(Virt.ClosePrice[i]-Virt.OpenPrice[i])*Virt.Lots[i]*MarketInfo(Virt.Symbol[i],MODE_TICKVALUE)/MarketInfo(Virt.Symbol[i], MODE_POINT)+Virt.Swap[i];
Virt.Comment[i]=Virt.Comment[i]+"[tp]";
is_closed=true;
}
}//End TakeProfit
if(Virt.StopLoss[i]>0){
if(MarketInfo(Virt.Symbol[i], MODE_BID)<=Virt.StopLoss[i]){
Virt.ClosePrice[i]=Virt.StopLoss[i]; // - Close price
Virt.Profit[i]=(Virt.ClosePrice[i]-Virt.OpenPrice[i])*Virt.Lots[i]*MarketInfo(Virt.Symbol[i],MODE_TICKVALUE)/MarketInfo(Virt.Symbol[i], MODE_POINT)+Virt.Swap[i];
Virt.Comment[i]=Virt.Comment[i]+"[sl]";
is_closed=true;
}
}//End StopLoss
break;
case OP_SELL:
Virt.CloseTime[i]=TimeCurrent(); // - Time of closing
Virt.ClosePrice[i]=MarketInfo(Virt.Symbol[i], MODE_ASK); // - Price of closing
Virt.Swap[i]=MathRound((Virt.CloseTime[i]-Virt.OpenTime[i])/(24*60*60))*MarketInfo(Virt.Symbol[i], MODE_SWAPSHORT)*Virt.Lots[i];
Virt.Profit[i]=(Virt.OpenPrice[i]-Virt.ClosePrice[i])*Virt.Lots[i]*MarketInfo(Virt.Symbol[i],MODE_TICKVALUE)/MarketInfo(Virt.Symbol[i], MODE_POINT)+Virt.Swap[i];
if(Virt.TakeProfit[i]>0){
if(MarketInfo(Virt.Symbol[i], MODE_ASK)<=Virt.TakeProfit[i]){
Virt.ClosePrice[i]=Virt.TakeProfit[i]; // - Close price
Virt.Profit[i]=(Virt.OpenPrice[i]-Virt.ClosePrice[i])*Virt.Lots[i]*MarketInfo(Virt.Symbol[i],MODE_TICKVALUE)/MarketInfo(Virt.Symbol[i], MODE_POINT)+Virt.Swap[i];
Virt.Comment[i]=Virt.Comment[i]+"[tp]";
is_closed=true;
}
}//End TakeProfit
if(Virt.StopLoss[i]>0){
if(MarketInfo(Virt.Symbol[i], MODE_ASK)>=Virt.StopLoss[i]){
Virt.ClosePrice[i]=Virt.StopLoss[i]; // - Close price
Virt.Profit[i]=(Virt.OpenPrice[i]-Virt.ClosePrice[i])*Virt.Lots[i]*MarketInfo(Virt.Symbol[i],MODE_TICKVALUE)/MarketInfo(Virt.Symbol[i], MODE_POINT)+Virt.Swap[i];
Virt.Comment[i]=Virt.Comment[i]+"[sl]";
is_closed=true;
}
}//End StopLoss
break;
case OP_BUYLIMIT:
if(MarketInfo(Virt.Symbol[i], MODE_ASK)<=Virt.OpenPrice[i]){
Virt.Type[i]=OP_BUY;
}
break;
case OP_SELLLIMIT:
if(MarketInfo(Virt.Symbol[i], MODE_BID)>=Virt.OpenPrice[i]){
Virt.Type[i]=OP_SELL;
}
break;
case OP_BUYSTOP:
if(MarketInfo(Virt.Symbol[i], MODE_ASK)>=Virt.OpenPrice[i]){
Virt.Type[i]=OP_BUY;
}
break;
case OP_SELLSTOP:
if(MarketInfo(Virt.Symbol[i], MODE_BID)<=Virt.OpenPrice[i]){
Virt.Type[i]=OP_SELL;
}
break;
}//End switch
if(Virt.Type[i]>1 && Virt.Type[i]<6) {
if(Virt.Expiration[i]>0) {
if(TimeCurrent()>Virt.Expiration[i]) {
Virt.Comment[i]=Virt.Comment[i]+"[expiration]";
is_closed=true;
}
}
}
if(is_closed){
for(j=i; j>=0; j--){
if(Virt.Status[j]==0) break;
}//Next j
Virt.Status[i]=0;
if(j<i-1){
j=j+1;
VirtualCopyPosition(j, 999);
VirtualCopyPosition(i, j);
VirtualCopyPosition(999, i);
}
}//End if(is_closed)
} else {
break;
}//End if(Virt.Status[i]==1)
}//Next i
if(is_changed) VirtualFileSave(filename);
}//VirtualUpdate()
//+------------------------------------------------------------------+
void VirtualCopyPosition(int FirstPosition, int SecondPosition){
//Procedure of copying of position to another cell of array
Virt.Ticket[SecondPosition]=Virt.Ticket[FirstPosition]; // - Number of order
Virt.OpenTime[SecondPosition]=Virt.OpenTime[FirstPosition]; // - Time of opening
Virt.Type[SecondPosition]=Virt.Type[FirstPosition]; // - Type of trade
Virt.Lots[SecondPosition]=Virt.Lots[FirstPosition]; // - Volume
Virt.Symbol[SecondPosition]=Virt.Symbol[FirstPosition]; // - Symbol
Virt.OpenPrice[SecondPosition]=Virt.OpenPrice[FirstPosition]; // - Price of opening
Virt.StopLoss[SecondPosition]=Virt.StopLoss[FirstPosition];
Virt.TakeProfit[SecondPosition]=Virt.TakeProfit[FirstPosition];
Virt.CloseTime[SecondPosition]=Virt.CloseTime[FirstPosition]; // - Time of closing
Virt.ClosePrice[SecondPosition]=Virt.ClosePrice[FirstPosition]; // - Price of closing
Virt.Swap[SecondPosition]=Virt.Swap[FirstPosition]; // - Swap
Virt.Profit[SecondPosition]=Virt.Profit[FirstPosition]; // - Profit in pipslots
Virt.Comment[SecondPosition]=Virt.Comment[FirstPosition]; // - Comments
Virt.MagicNumber[SecondPosition]=Virt.MagicNumber[FirstPosition]; // - Magic number
Virt.Expiration[SecondPosition]=Virt.Expiration[FirstPosition]; // - Date of canceling pending order
Virt.Status[SecondPosition]=Virt.Status[FirstPosition]; // - Status of order: 1 - open position/pending order; 0 - closed position/pending order
}//VirtualCopyPosition()
//+------------------------------------------------------------------+
int VirtualSend(string symbol, int cmd, double volume, double price,
int slippage, double stoploss, double takeprofit, string comment="",
int magic=0, datetime expiration=0, string filename="virtual.csv") {
/* Main function that is used for opening positions and placing pending orders.
Returns ticket number, which is assigned to order by the trade server, or -1 in case of failing.
Parameters:
symbol - Name of financial instrument a trade operation is performed by.
cmd - Trade operation. Can have any value of trade operations.
volume - Number of lots.
price - Open price.
slippage - Maximum acceptable deviation of price in points for market orders (buy or sell orders).
stoploss - Price of closing position at reaching a level of unprofitableness (0 if there is no such level).
takeprofit - Price of closing the position at reaching a level of profitability (0 if there is no such level).
comment - Text of comment to the order. The last part of comment can be changed by the trade server.
magic - Magic number of the order. Can be used as an identifier determined by user.
expiration - Expiration time of pending order.
filename - Name of the file of virtual trades from directory TerminalPath()+"\experts\files" */
//---------------------------------------------
//Block of checks:
if(cmd==OP_BUY){
//Open price of buying should be near Ask +- slippage
if((price>MarketInfo(symbol,MODE_ASK)+slippage*MarketInfo(symbol,MODE_POINT))||
(price<MarketInfo(symbol,MODE_ASK)-slippage*MarketInfo(symbol,MODE_POINT))){
Err.Number = 1;
Err.Description = "Open price of position is too far from market";
return(-1);
}
}else if(cmd==OP_SELL){
if((price>MarketInfo(symbol,MODE_BID)+slippage*MarketInfo(symbol,MODE_POINT))||
(price<MarketInfo(symbol,MODE_BID)-slippage*MarketInfo(symbol,MODE_POINT))){
Err.Number = 1;
Err.Description = "Open price of position is too far from market";
return(-1);
}
}else if(cmd==OP_BUYSTOP){
if(price<=MarketInfo(symbol,MODE_ASK)+MarketInfo(symbol,MODE_STOPLEVEL)*MarketInfo(symbol,MODE_POINT)){
Err.Number = 2;
Err.Description = "Open price of pending order is too close to market";
return(-1);
}
}else if(cmd==OP_SELLSTOP){
if(price>=MarketInfo(symbol,MODE_BID)-MarketInfo(symbol,MODE_STOPLEVEL)*MarketInfo(symbol,MODE_POINT)){
Err.Number = 2;
Err.Description = "Open price of pending order is too close to market";
return(-1);
}
}else if(cmd==OP_BUYLIMIT){
if(price>=MarketInfo(symbol,MODE_ASK)-MarketInfo(symbol,MODE_STOPLEVEL)*MarketInfo(symbol,MODE_POINT)){
Err.Number = 2;
Err.Description = "Open price of pending order is too close to market";
return(-1);
}
}else if(cmd==OP_SELLLIMIT){
if(price<=MarketInfo(symbol,MODE_BID)+MarketInfo(symbol,MODE_STOPLEVEL)*MarketInfo(symbol,MODE_POINT)){
Err.Number = 2;
Err.Description = "Open price of pending order is too close to market";
return(-1);
}
}
if(stoploss!=0.0){
if((cmd==OP_BUY) || (cmd==OP_BUYSTOP) || (cmd==OP_BUYLIMIT)){// Buy
if(price-stoploss<=MarketInfo(symbol,MODE_STOPLEVEL)*MarketInfo(symbol,MODE_POINT)){
Err.Number = 3;
Err.Description = "StopLoss or TakeProfit level is too close to price";
return(-1);
}
}else if((cmd==OP_SELL) || (cmd==OP_SELLSTOP) || (cmd==OP_SELLLIMIT)){// Sell
if(stoploss-price<=MarketInfo(symbol,MODE_STOPLEVEL)*MarketInfo(symbol,MODE_POINT)){
Err.Number = 3;
Err.Description = "StopLoss or TakeProfit level is too close to price";
return(-1);
}
}
}
if(takeprofit!=0.0){
if((cmd==OP_BUY) || (cmd==OP_BUYSTOP) || (cmd==OP_BUYLIMIT)){// Buy
if(takeprofit-price<=MarketInfo(symbol,MODE_STOPLEVEL)*MarketInfo(symbol,MODE_POINT)){
Err.Number = 3;
Err.Description = "StopLoss or TakeProfit level is too close to price";
return(-1);
}
}else if((cmd==OP_SELL) || (cmd==OP_SELLSTOP) || (cmd==OP_SELLLIMIT)){// Sell
if(price-takeprofit<=MarketInfo(symbol,MODE_STOPLEVEL)*MarketInfo(symbol,MODE_POINT)){
Err.Number = 3;
Err.Description = "StopLoss or TakeProfit level is too close to price";
return(-1);
}
}
}
if((volume<MarketInfo(symbol, MODE_MINLOT))||
(volume>MarketInfo(symbol, MODE_MAXLOT))){
Err.Number = 4;
Err.Description = "Incorrect volume";
return(-1);
}
if(expiration<=TimeCurrent() && expiration!=0){
Err.Number = 5;
Err.Description = "Incorrect expiration date";
return(-1);
}
//End of block of checks
//---------------------------------------------
//Protection from array overflow
int i, j, k;
VirtualFileLoad(filename);
if(Virt.Count>998){
//Delete all canceled pending orders
for(i=0; i<Virt.Count; i++){
if((Virt.Type[i]>1) && (Virt.Status[i]==0)) {
//All trades located below this pending order are moved one level up:
for(j=i; j<Virt.Count-1; j++) {
Virt.Ticket[j] = Virt.Ticket[j+1];
Virt.OpenTime[j] = Virt.OpenTime[j+1];
Virt.Type[j] = Virt.Type[j+1];
Virt.Lots[j] = Virt.Lots[j+1];
Virt.Symbol[j] = Virt.Symbol[j+1];
Virt.OpenPrice[j] = Virt.OpenPrice[j+1];
Virt.StopLoss[j] = Virt.StopLoss[j+1];
Virt.TakeProfit[j] = Virt.TakeProfit[j+1];
Virt.CloseTime[j] = Virt.CloseTime[j+1];
Virt.ClosePrice[j] = Virt.ClosePrice[j+1];
Virt.Swap[j] = Virt.Swap[j+1];
Virt.Profit[j] = Virt.Profit[j+1];
Virt.Comment[j] = Virt.Comment[j+1];
Virt.MagicNumber[j] = Virt.MagicNumber[j+1];
Virt.Expiration[j] = Virt.Expiration[j+1];
Virt.Status[j] = Virt.Status[j+1];
}//Next j
Virt.Count--;
}
}//Next i
//Searching for first closed trade
for(i=0; i<Virt.Count; i++){
if((Virt.Type[i]<2) && (Virt.Status[i]==0)) {
break;
}
}//Next i
if(i==Virt.Count){
Err.Number = 402;
Err.Description = "Number of open trades exceeded the maximum allowed level! You should remake the trading system.";
return(-1);
}else{
//Searching for the second closed trade
for(j=i+1; j<Virt.Count; j++) {
if(Virt.Status[j]==0) {
break;
}
}//Next j
if(j==Virt.Count){
Err.Number = 402;
Err.Description = "Number of open trades exceeded the maximum allowed level! You should remake the trading system.";
return(-1);
}else{
//Bring the result of 2 trades (1-st and 2-nd) in the first closed trade:
Virt.Ticket[i] = Virt.Ticket[j];
Virt.OpenTime[i] = Virt.OpenTime[j];
Virt.Type[i] = -1;
Virt.Lots[i] = Virt.Lots[i]+Virt.Lots[j];
Virt.Symbol[i] = "";
Virt.OpenPrice[i] = 0;
Virt.StopLoss[i] = 0;
Virt.TakeProfit[i] = 0;
Virt.CloseTime[i] = Virt.CloseTime[j];
Virt.ClosePrice[i] = 0;
Virt.Swap[i] = Virt.Swap[i]+Virt.Swap[j];
Virt.Profit[i] = Virt.Profit[i]+Virt.Profit[j];
Virt.Comment[i] = "Archive";
Virt.MagicNumber[i] = Virt.MagicNumber[j];
Virt.Expiration[i] = Virt.Expiration[j];
//All trades located below the second closed trade are moved one level upwards:
for(k=j; k<Virt.Count-1; k++) {
Virt.Ticket[k] = Virt.Ticket[k+1];
Virt.OpenTime[k] = Virt.OpenTime[k+1];
Virt.Type[k] = Virt.Type[k+1];
Virt.Lots[k] = Virt.Lots[k+1];
Virt.Symbol[k] = Virt.Symbol[k+1];
Virt.OpenPrice[k] = Virt.OpenPrice[k+1];
Virt.StopLoss[k] = Virt.StopLoss[k+1];
Virt.TakeProfit[k] = Virt.TakeProfit[k+1];
Virt.CloseTime[k] = Virt.CloseTime[k+1];
Virt.ClosePrice[k] = Virt.ClosePrice[k+1];
Virt.Swap[k] = Virt.Swap[k+1];
Virt.Profit[k] = Virt.Profit[k+1];
Virt.Comment[k] = Virt.Comment[k+1];
Virt.MagicNumber[k] = Virt.MagicNumber[k+1];
Virt.Expiration[k] = Virt.Expiration[k+1];
Virt.Status[k] = Virt.Status[k+1];
}//Next k
Virt.Count--;
}
}
}//End of protection from array overflow
//---------------------------------------------
//Adding new position into the array
Virt.Count++;
Virt.Ticket[Virt.Count-1] = VirtualHighTicket()+1;
Virt.OpenTime[Virt.Count-1] = TimeCurrent();
Virt.Type[Virt.Count-1] = cmd;
Virt.Lots[Virt.Count-1] = volume;
Virt.Symbol[Virt.Count-1] = symbol;
Virt.OpenPrice[Virt.Count-1] = price;
Virt.StopLoss[Virt.Count-1] = stoploss;
Virt.TakeProfit[Virt.Count-1] = takeprofit;
Virt.Comment[Virt.Count-1] = comment;
Virt.MagicNumber[Virt.Count-1] = magic;
Virt.Expiration[Virt.Count-1] = expiration;
Virt.Status[Virt.Count-1] = 1;
//---------------------------------------------
//Save changes
VirtualFileSave(filename);
return(Virt.Ticket[Virt.Count-1]);
}//VirtualSend()
//+------------------------------------------------------------------+
int VirtualHighTicket(){
//Searching for a young ticket
int i, j;
for(i=0; i<Virt.Count; i++){
if(Virt.Ticket[i]>j){
j=Virt.Ticket[i];
}
}//Next i
return(j);
}//VirtualHighTicket()
//+------------------------------------------------------------------+
int VirtualFileLoad(string file) {
//The function loads trades from a file to the array of trades
//and returns the number of loaded lines.
if(FastTest){
if(IsTesting()) return(0);
}
int k, Count;
string buffer[];
ArrayResize(buffer,VirtBufferSize*1000);
int handle=FileOpen(file,FILE_CSV|FILE_READ,';');
if(handle<1) {
Err.Number = 401;
Err.Description = "File of trades is not found";
return(-1);
} else {
Count=0;
//Read the file
while(!FileIsEnding(handle)){
buffer[Count]=FileReadString(handle);
Count++;
}
Count--;
FileClose(handle);
//Fill the array
Virt.Count=0;
k=VirtBufferSize;
//Print("Loaded ",Count/VirtBufferSize-1," lines");
while(Virt.Count<Count/VirtBufferSize-1) {
Virt.Ticket[Virt.Count]= StrToInteger(buffer[k]); // - Number of order
Virt.OpenTime[Virt.Count] = StrToTime(buffer[k+1]); // - Time of opening
Virt.Type[Virt.Count] = StrToInteger(buffer[k+2]); // - Type of trade
Virt.Lots[Virt.Count] = StrToDouble(buffer[k+3]); // - Volume
Virt.Symbol[Virt.Count] = buffer[k+4]; // - Symbol
Virt.OpenPrice[Virt.Count] = StrToDouble(buffer[k+5]); // - Price of opening
Virt.StopLoss[Virt.Count] = StrToDouble(buffer[k+6]);
Virt.TakeProfit[Virt.Count] = StrToDouble(buffer[k+7]);
Virt.CloseTime[Virt.Count] = StrToTime(buffer[k+8]); // - Time of closing
Virt.ClosePrice[Virt.Count] = StrToDouble(buffer[k+9]); // - Price of closing
Virt.Swap[Virt.Count] = StrToDouble(buffer[k+10]); // - Swap
Virt.Profit[Virt.Count] = StrToDouble(buffer[k+11]); // - Profit in pipslots
Virt.Comment[Virt.Count] = buffer[k+12]; // - Comments
Virt.MagicNumber[Virt.Count] = StrToInteger(buffer[k+13]);//- Magic number
Virt.Expiration[Virt.Count] = StrToTime(buffer[k+14]); // - Date of canceling pending order
Virt.Status[Virt.Count] = StrToInteger(buffer[k+15]); // - State of order: 1 - open; 0 - closed
k=k+VirtBufferSize;
Virt.Count++;
}
return(Virt.Count);
}
}//VirtualFileLoad()
//+------------------------------------------------------------------+
void VirtualFileSave(string file) {
//Procedure of saving the array of trades to a specified file.
if(FastTest){
if(IsTesting()) return(0);
}
int Count=0;
int handle=FileOpen(file,FILE_CSV|FILE_WRITE,';');
FileWrite(handle, "Order name","Open time","Type","Volume","Symbol","Open price","S/L","T/P",
"Close time","Close price","Swap","Profit","Comment","Magic number","Expiration","State");
//Saving to the file
while(Count<Virt.Count) {
//Probably the transformation of data is necessary
FileWrite(handle,
Virt.Ticket[Count],
TimeToStr(Virt.OpenTime[Count]),
Virt.Type[Count],
Virt.Lots[Count],
Virt.Symbol[Count],
Virt.OpenPrice[Count],
Virt.StopLoss[Count],
Virt.TakeProfit[Count],
TimeToStr(Virt.CloseTime[Count]),
Virt.ClosePrice[Count],
Virt.Swap[Count],
Virt.Profit[Count],
Virt.Comment[Count],
Virt.MagicNumber[Count],
TimeToStr(Virt.Expiration[Count]),
Virt.Status[Count]
);
Count++;
}
FileClose(handle);
//Print("Written ",Count," lines");
}//VirtualFileSave()
//+------------------------------------------------------------------+
bool VirtualExist(datetime TimeOpenCandle, int fMagic=0){
VirtualFilter(VIRT_TRADES, -1, -1, Symbol(), fMagic);
for(int i=0; i<Virt.Filter.Count; i++){
if(Virt.OpenTime[Virt.Filter[i]]>=TimeOpenCandle){
return(true);
}
}//Next i
return(false);
}//VirtualExist()
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+