snowseed-lib





//:adic:
double standardLot = 1;

// Value of the take profit, on a chart:
// dTp = Bid - dTakeProfit; 
// or 
// dTp = Ask + dTakeProfit;

double dTp = 0;

// Used to deside, if this is the beginning of a new bar.

int nBars;

// An expert runs 10 * nMagic seconds after the bar end
// This way we reduce competition between experts and
// avoid deadlocks

int nDelaySeconds = 10;

// Slippage

int nSlip = 5;

// Used to calculate the size of a lot, if bUseMm is
// set to 0, the lot size is always 0.1
// We strongly recommend that you use your own 
// money management system, this is just a simple 
// placeholder

double dProfit = 0;

// Used to figure out if we have enough money to trade
// We strongly recommend that you use your own 
// money management system, this is just a simple 
// placeholder

double dInitAmount = 1000;

// A standart lot size

double dLotSize = 1; //lotSize; //0.1;

// Magic number. Unique for a combination of expert -
// currency - timeframe

int nMagic = 0;

// Report is not part of the trading, but only a 
// function to write transactions to a file. We 
// do it once a day

bool bReportDone = false;

// This variable contains 0, or the magic number 
// of currently trading expert

string strTradeSemaphore = "TradeSemaphore";

// ------

/* This function creates a file with the name, 
that is unique for an expert-currency-timeframe, 
and writes trading history in it.

Note, that we only same the profit of operation(s) 
here. If you want to save additional information, 
like order open dates or swaps, you need to modify 
the code below.

The strFileName contains the file name prefix, 
usually it is the name of an expert.
*/

void Report(string strFileName, int nMagic, 
	bool& bReportDone)
{
	// Do it only during run time trading
	if(IsTesting())
		return;

	// Save once a day, at 0 hours nMagic / 2 minutes
	if(Hour() == 0 && Minute() >= nMagic / 2)
	{
		// Make sure it only happens once, even 
		// if we have 2 or more ticks satisfying 
		// the condition above

		if(bReportDone == false)
		{
			int hFile = FileOpen(strFileName + "_" + Symbol() + "_" + Period() + ".rpt", FILE_BIN | FILE_WRITE, ',');
			
			string str = "CloseDateTime,Buy,Sell\r\n";
			FileWriteString(hFile, str, StringLen(str)); 

			// Write the entire trading history to the 
			// file. 
			// Note: make sure all trading history is 
			// available (MT4-Terminal-Account History)
			
			for(int nCnt = 0; nCnt < HistoryTotal(); 
				nCnt++)
			{
				OrderSelect(nCnt, SELECT_BY_POS, MODE_HISTORY);	
				if(OrderMagicNumber() == nMagic && OrderType() <= OP_SELL && OrderSymbol() == Symbol())
				{
					str = TimeToStr(OrderCloseTime(), TIME_DATE|TIME_MINUTES);
					
					if(OrderType() == OP_BUY) str = str + "," + OrderProfit() + ",0";
					else
						str = str + ",0," + OrderProfit();
					
					str = str + " \r\n ";
					
					FileWriteString(hFile, str, 
						StringLen(str));
				}
			}			

			FileFlush(hFile); 
			FileClose(hFile); 
			
			bReportDone = true;
		}
	}
	else if(Hour() != 0)	// Reset the flag
		bReportDone = false;
}

// ------

// A simple placeholder for a real money management
// algorythm. In expert, set bUseMm to false or
// true. A default lot size is 0.1.

double GetLotSize(double dInitFraction = 0.1, 
	double dProfitFraction = 0.1)
{
	double dLot = standardLot;   //0.1;
	
	if(bUseMm)
	{
		dLot  = (dInitFraction * dInitAmount + dProfitFraction * dProfit) / 1000;

		dLot = MathFloor(dLot * 10) / 10;
	
		if(dLot < standardLot)   dLot = standardLot;
	}
	
	return(dLot);
}

// ------

/* Buy() and Sell() functions use dStopLoss and 
	dTakeProfit, that are assigned in the expert.

We are going to try to open an order for 10 times, 
	because sometimes the server or the Internet 
	connection fails.

Note the call to SaveComment() function. If the 
	order was not opened, when you think it should 
	be, you may check the corresponding file in 
	experts/files directory. It will give you the 
	error number and some additional hints on what 
	happened.

Note, that it is possible to use more than one 
	magic number with the same 
	expert-currency-timeframe, in which case
	you need to explicitely pass it as a 
	nMagicNumber parameter.

dLot is a coefficient (a multiplier) used to 
	increase the lot size, usually, you will use 
	it for trading contests, or if you are 
	overconfident in the performance (drawdowns) 
	of your expert.
*/

int Sell(string strExpertName, double dLot = 0, 
	int nMagicNumber = -1)
{
	int nResult = -1;
	
	if(nMagicNumber == -1)
		nMagicNumber = nMagic;

	if(dLot == 0)
		dLotSize = GetLotSize();
	else
		dLotSize = dLot * GetLotSize();
	
	// Note, that this is a simple placeholder for a 
	// real money management algorythm. We will discuss
	// money management in a separate article.
	if(AccountFreeMargin() < dLotSize * dInitAmount 
		|| AccountFreeMargin() < 500)
		return(nResult);

	double dTp;
	if(dTakeProfit == 0)
		dTp = 0;
	else
		dTp = Bid - dTakeProfit;

	// We try 10 times
	for(int nTry = 0; nTry < 10; nTry++)
	{
		SaveComment(" \r\n " + Day() + "." + Month() + "." + Year() + " " + Hour() + ":" + 
			Minute() + ":" + Seconds());
		SaveComment(" Trying to sell, attempt " + nTry + " \r\n ");
		SaveComment("\r\nAsk: " + Ask + ", StopLoss: " + dStopLoss + ", TakeProfit: " + dTakeProfit + " \r\n ");
		double vAdicStopLoss;
		if (dStopLoss == 0)   vAdicStopLoss = 0;
		else {
         if (dStopLoss >= 1)  {
            vAdicStopLoss = Bid + dStopLoss*Point;		 
         }
   		else  vAdicStopLoss = Bid + dStopLoss;
		}		
		nResult = OrderSend(Symbol(), OP_SELL, dLotSize, Ask, nSlip, vAdicStopLoss, dTp, strExpertName, nMagicNumber, 0, Aqua);		
		//nResult = OrderSend(Symbol(), OP_SELL, dLotSize, Bid, nSlip, Bid + dStopLoss*Point, dTp, strExpertName, nMagicNumber, 0, OrangeRed);
		
		// Wait 10 seconds before the next try.
		Sleep(10000);

		// If trade failed, refresh rates and try again
		if(nResult != -1)
		{
			SaveComment(" successfull\r\n");
			break;
		}
		else
		{
			SaveComment(" failed, error " + GetLastError() 
				+ " \r\n ");
			RefreshRates();
		}
	}	
	
	// If all 10 attempts failed, write additional info
	// to the report file
	if(nResult == -1)
	{
		int nError = GetLastError();
		Alert(strExpertName + " sell error: " + nError + " \r\n " + Bid + ", " + vAdicStopLoss + ", " + dTp);
		SaveComment(strExpertName + " sell error: " + nError + " \r\n " + Bid + ", " + vAdicStopLoss + ", " + dTp);
	}
	
	return(nResult);
}

// ------

// The structure of Buy() is similar to Sell(), 
// see Sell() for comments

int Buy(string strExpertName, double dLot = 0, 
	int nMagicNumber = -1)
{
	int nResult = -1;
	
	if(nMagicNumber == -1)
		nMagicNumber = nMagic;

	if(dLot == 0)
		dLotSize = GetLotSize();
	else
		dLotSize = dLot * GetLotSize();
	
	if(AccountFreeMargin() < dLotSize * dInitAmount 
		|| AccountFreeMargin() < 500)
		return(nResult);

	double dTp;
	if(dTakeProfit == 0)
		dTp = 0;
	else
		dTp = Ask + dTakeProfit;

	for(int nTry = 0; nTry < 10; nTry++)
	{
		SaveComment(" \r\n " + Day() + "." + Month() + "." + Year() + " " + Hour() + ":" + Minute() + ":" + Seconds());
		SaveComment(" Trying to buy, attempt " + nTry + " \r\n ");
		SaveComment("\r\nBid: " + Bid + ", StopLoss: " + dStopLoss + ", TakeProfit: " + dTakeProfit);
		double vAdicStopLoss;
		if (dStopLoss == 0)   vAdicStopLoss = 0;
		else {
         if (dStopLoss >= 1)  {
            vAdicStopLoss = Ask - dStopLoss*Point;		 
         }
   		else  vAdicStopLoss = Ask - dStopLoss;
		}		
		nResult = OrderSend(Symbol(), OP_BUY, dLotSize, Ask, nSlip, vAdicStopLoss, dTp, strExpertName, nMagicNumber, 0, Aqua);
		//:adic:nResult = OrderSend(Symbol(), OP_BUY, dLotSize, Ask, nSlip, Ask - dStopLoss*Point, dTp, strExpertName, nMagicNumber, 0, Aqua);

		Sleep(10000);
		if(nResult != -1)
		{
			SaveComment(" successfull\r\n");
			break;
		}
		else
		{
			SaveComment(" failed, error " + GetLastError() + " \r\n ");
			RefreshRates();
		}
	}	

	if(nResult == -1)
	{
		int nError = GetLastError();
		Alert(strExpertName + " buy error: " + nError + " \r\n " + Ask + ", " + vAdicStopLoss + ", " + dTp);

		SaveComment(strExpertName + " buy error: " + nError + " \r\n " + Ask + ", " + vAdicStopLoss + ", " + dTp);
	}

	return(nResult);
}

// ------

/* We use this function to modify orders. It uses 
	dTrailingStop, assigned in the expert. When the 
	price goes away from the stop loss more than 5
	points (from the stop loss to stop loss + 5 points), 
	we move the stop closer to the price.
*/

void ModifyOrders()
{
	if(dTrailingStop == 0)
		return;

	// Scan all opened orders, looking for an 
	// order with "our" magic number

	for(int nCnt = 0; nCnt < OrdersTotal(); 
		nCnt++)
	{
		OrderSelect(nCnt, SELECT_BY_POS, 
			MODE_TRADES);
		if(OrderMagicNumber() == nMagic)
		{
			if(OrderType() == OP_BUY)
			{
				if(OrderStopLoss() < Bid - 
					dTrailingStop - 5 * Point)
				{
					OrderModify(OrderTicket(), 
						OrderOpenPrice(), 
						Bid - dTrailingStop, 
						OrderTakeProfit(), 
						0, Aqua);

					// Note: we assume, that there 
					// is only one opened order with 
					// this magic number in a time. 
					// If it is not so, comment the 
					// "break".
					break;
				}
			}
			
			if(OrderType() == OP_SELL)
			{
				if(OrderStopLoss() > Ask + 
					dTrailingStop + 5 * Point)
				{
					OrderModify(OrderTicket(), 
						OrderOpenPrice(), 
						Ask + dTrailingStop, 
						OrderTakeProfit(), 
						0, OrangeRed);

					break;
				}
			}
		}
	}
}

// ------

// This function determines if this is the beginning
// of a new bar. Note, that in order to avoid conflicts
// between experts, we wait few seconds after the bar
// start, the delay is unique for each expert-currency-
// timeframe

bool IsBarEnd()
{
	bool bIsBarEnd = false;
	if(nBars != Bars)
	{
		if(IsTesting() || (!IsTesting() && 
			CurTime() > Time[0] + nMagic * nDelaySeconds))
		{
			bIsBarEnd = true;
			nBars = Bars;
		}
	}
	
	return(bIsBarEnd);
}

// ------

/* The magic number of the currently trading expert 
	(or 0) is stored in the global variable. In a cycle,
	our expert tries to set its magic number to this global 
	variable, and when successfull, exits the cycle.
*/

void CheckTradeSemaphore()
{
	if(!IsTesting())
	{
		while(!IsStopped())
		{
			GlobalVariableSetOnCondition(
				strTradeSemaphore, nMagic, 
				0.0);

			if(GlobalVariableGet(strTradeSemaphore) 
				== nMagic)
				break;

			Sleep(1000);
		}
	
		RefreshRates();
	}
}

// ------

/* Attempts to close an order, for 10 times. 
	Comments written to the file with SaveComment()
	will help you to debug the expert, if it fails
	to close an order.
*/

void CloseBuy(string strExpertName)
{
	int nTicket = OrderTicket();
	SaveComment(" \r\n \tAttempting to close long position, ticket: " + nTicket + " \r\n ");
	
	for(int nTry = 0; nTry < 10; nTry++)
	{
		SaveComment(Day() + "." + Month() + "." + 
			Year() + " " + Hour() + ":" + Minute() + ":" + Seconds());
		int nResult = OrderClose(OrderTicket(), OrderLots(), Bid, nSlip, Aqua);
		
		Sleep(10000);
		if(nResult == -1)
		{
			int nError = GetLastError();
			Alert(strExpertName + ", error: " + nError);
			SaveComment(strExpertName + ", error: " + nError);
		}
		
		bool bClosed = true;
		for(int nOrderNo = OrdersTotal() - 1; 
			nOrderNo >= 0; nOrderNo--)
		{
			OrderSelect(nOrderNo, SELECT_BY_POS, MODE_TRADES);
			if(OrderTicket() == nTicket)
			{
				bClosed = false;
				break;
			}
		}
		
		if(bClosed == true)
		{
			SaveComment(
				" \r\n \tNo more orders with this ticket No");
			break;
		}
		else
		{
			SaveComment(" \r\n \tOrder with this ticket still present, trying again");
			RefreshRates();
		}
	}
}

// ------

// Same logic as in CloseBuy()

void CloseSell(string strExpertName)
{
	int nTicket = OrderTicket();
	SaveComment(" \r\n \tAttempting to close short position, ticket: " + nTicket + " \r\n ");
	
	for(int nTry = 0; nTry < 10; nTry++)
	{
		SaveComment(Day() + "." + Month() + "." + Year() + 
			" " + Hour() + ":" + Minute() + ":" + Seconds());
		int nResult = OrderClose(OrderTicket(), 
			OrderLots(), Ask, nSlip, OrangeRed);
		
		Sleep(10000);
		if(nResult == -1)
		{
			int nError = GetLastError();
			Alert(strExpertName + ", error: " + nError);
			SaveComment(strExpertName + ", error: " + nError);
		}
		
		bool bClosed = true;
		for(int nOrderNo = OrdersTotal() - 1; 
			nOrderNo >= 0; nOrderNo--)
		{
			OrderSelect(nOrderNo, SELECT_BY_POS, MODE_TRADES);
			if(OrderTicket() == nTicket)
			{
				bClosed = false;
				break;
			}
		}
		
		if(bClosed == true)
		{
			SaveComment(" \r\n \tNo more orders with this ticket No");
			break;
		}
		else
		{
			SaveComment(" \r\n \tOrder with this ticket still present, trying again");
			RefreshRates();
		}
	}
}

// ------

// Open a file with unique file name, add a string
// to the end of this file

void SaveComment(string strComment)
{
	if(!IsTesting())
	{
		int hFile = FileOpen("__test_" + strExpert + 
			"_" + Symbol() + ".txt", 
			FILE_BIN | FILE_READ | FILE_WRITE, '\t');	
	
		FileSeek(hFile, 0, SEEK_END);
		FileWriteString(hFile, strComment, 
			StringLen(strComment));
	
		FileClose(hFile);
	}
}

// ------

// Delete pending order, logic is the same as in
// CloseBuy()

int DeletePending()
{
	int nResult = -1;
	
	for(int nTry = 0; nTry < 10; nTry++)
	{
		SaveComment(" \r\n " + Day() + "." + Month() + 
			"." + Year() + " " + Hour() + ":" + 
			Minute() + ":" + Seconds());
		SaveComment(" Trying to delete pending " + 
			OrderTicket() + ", attempt " + nTry + " \r\n ");
		
		nResult = OrderDelete(OrderTicket());
		
		Sleep(10000);
		if(nResult != -1)
		{
			SaveComment(" successfull\r\n");
			break;
		}
		else
			SaveComment(" failed, error " + 
				GetLastError() + " \r\n ");
	}	
	
	if(nResult == -1)
	{
		int nError = GetLastError();
		Alert(strExpert + " delete pending, error: " 
			+ nError + " \r\n ");
		SaveComment(strExpert + 
			" delete pending, error: " + nError + " \r\n ");
	}
	
	return(nResult);
}





Sample





Analysis



Market Information Used:

Series array that contains open time of each bar


Indicator Curves created:


Indicators Used:



Custom Indicators Used:

Order Management characteristics:

It automatically opens orders when conditions are reached
Checks for the total of open orders
It can change open orders parameters, due to possible stepping strategy
It Closes Orders by itself

Other Features:

Uses files from the file system
It writes information to file
It issuies visual alerts to the screen