//+------------------------------------------------------------------+
//|                                                TrueRandChart.mq4 |
//|                                  Copyright © 2011, Leif Karlsson |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2011, Leif Karlsson"
#property link      ""

#property show_inputs

//+------------------------------------------------------------------+
extern int bars = 10000;
extern int digits = 4;
extern int avgVolume = 30;
extern double tickSize = 0.0001;
extern double startPrice = 1.0;
extern string symbolName = "rndChart";
extern bool refresh = false;

//+------------------------------------------------------------------+
#define INTERNET_FLAG_PRAGMA_NOCACHE    0x00000100
#define INTERNET_FLAG_NO_CACHE_WRITE    0x04000000
#define INTERNET_FLAG_RELOAD            0x80000000
#define INTERNET_OPEN_TYPE_DIRECT       0x00000001

#import "wininet.dll"

int InternetOpenA(
	string	 sAgent,
	int	    lAccessType,
	string	 sProxyName="",
	string	 sProxyBypass="",
	int	    lFlags=0
);

int InternetOpenUrlA(
	int	    hInternetSession,
	string	 sUrl, 
	string	 sHeaders="",
	int	    lHeadersLength=0,
	int	    lFlags=0,
	int	    lContext=0 
);

int InternetReadFile(
	int	    hFile,
	string	 sBuffer,
	int	    lNumBytesToRead,
	int&      lNumberOfBytesRead[]
);

int InternetCloseHandle(
	int	hInet
);
#import ""

//+------------------------------------------------------------------+
bool errorFlag = false;

//+------------------------------------------------------------------+
int start() {

   int hHst, time, vol, hstUnused[13], ticks, r;
   double hi, lo, op, cl; 
   
   vol = 1;   
   
   // check if file exist
   hHst = FileOpenHistory(symbolName + "2.hst", FILE_BIN|FILE_READ);
   FileClose(hHst);
   
   // continue on old chart?
   if(!refresh && hHst != -1) {
   
      hHst = FileOpenHistory(symbolName + "2.hst", FILE_BIN|FILE_READ|FILE_WRITE);   
      
      FileSeek(hHst, -16, SEEK_END);
      cl = FileReadDouble(hHst, DOUBLE_VALUE);      
      hi = cl;
      lo = cl;
      op = cl;
      
      FileSeek(hHst, 0, SEEK_END);
      time = 60*(FileTell(hHst) - 148)/44;
   }
   // or a new chart.
   else {
         
      hHst = FileOpenHistory(symbolName + "2.hst", FILE_BIN|FILE_WRITE);
   
      FileWriteInteger(hHst, 400, LONG_VALUE); 			 // Version        4
	   FileWriteString(hHst, "", 64);					    // Copyright      64
	   FileWriteString(hHst, symbolName, 12);			    // Symbol         12
	   FileWriteInteger(hHst, 2, LONG_VALUE);	          // Period         4
	   FileWriteInteger(hHst, digits, LONG_VALUE);		 // Digits         4
      FileWriteInteger(hHst, 0, LONG_VALUE);			    // Time Sign      4
      FileWriteInteger(hHst, 0, LONG_VALUE);			    // Last Sync      4
      FileWriteArray(hHst, hstUnused, 0, 13);			 // Unused         13*4
      
      hi = startPrice;
      lo = startPrice;
      op = startPrice;
      cl = startPrice;   
      time = 0;
   }
	   
   // main loop	   
   while(time < bars*60 && !errorFlag) {
   
      r = RndChar() + 1;
      ticks = 2 + avgVolume*LogNormal(r/256.0);
   
      while(vol < ticks && !errorFlag) {
      
   		if(RndBit()) cl += tickSize;
	     	else cl -= tickSize;
      
         hi = MathMax(hi, cl);
         lo = MathMin(lo, cl);
         vol++;
      }
      
      hi = NormalizeDouble(hi, digits);
      lo = NormalizeDouble(lo, digits);
      op = NormalizeDouble(op, digits);
      cl = NormalizeDouble(cl, digits);
      
		FileWriteInteger(hHst, time, LONG_VALUE);		// Time  4
		FileWriteDouble(hHst, op, DOUBLE_VALUE);     // Open  8
		FileWriteDouble(hHst, lo, DOUBLE_VALUE);		// Low   8
		FileWriteDouble(hHst, hi, DOUBLE_VALUE);		// High  8
		FileWriteDouble(hHst, cl, DOUBLE_VALUE);		// Close 8
		FileWriteDouble(hHst, vol, DOUBLE_VALUE);		// Volume 8		
		
 		if(RndBit()) cl += tickSize;
    	else cl -= tickSize;
				
      op = cl;
      hi = cl;
      lo = cl;
      vol = 1;
      
      time += 60;  
   }
   // --
   
   FileClose(hHst);
   
   Alert("Chart done!");
   
   return(0);
}
//+------------------------------------------------------------------+
// get random bit stream from www.random.org, as a string.
// the bits are separated by unix style new lime, (0x0ah)
string GetRndStr(int len, bool new=true) {

   static string str = "111111111111111111111111111111111";

   int bufferLen = 100, lReturn[1], hSession, hInternet;
   string buffer = "01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789";

   string URL = "http://www.random.org/integers/?num=" + len + "&min=0&max=1&col=1&base=2&format=plain&rnd=new";
   string internetAgent = "MT4 / " + WindowExpertName();
   string internetHeader = "Accept: text\r\n" +
                           "Accept-Language: en\r\n" +
                           "Accept-Encoding: text\r\n" +
                           "Accept-Charset: ISO-8859-1,utf-8\r\n" +
                           "Keep-Alive: 500\r\n" +
                           "Connection: keep-alive\r\n\r\n";
                           
   if(!new && StringLen(str) >= len) return(str);                           

   hSession = InternetOpenA(internetAgent, INTERNET_OPEN_TYPE_DIRECT, "0", "0", 0);  
   hInternet = InternetOpenUrlA(hSession, URL, internetHeader, -1, INTERNET_FLAG_NO_CACHE_WRITE | INTERNET_FLAG_PRAGMA_NOCACHE | INTERNET_FLAG_RELOAD, 0);
   
   if(hSession == 0 || hInternet == 0) {
      Alert("Error opening URL: " + URL);
      errorFlag = true;
      return("111111111111111111111111111111111111111111111111111111111111111111");
   }        
   
   str = "";
	while(InternetReadFile(hInternet, buffer, bufferLen, lReturn) != 0) {
     if(lReturn[0] == 0) break;
	  str = str + StringSubstr(buffer, 0, lReturn[0]);
   }
   
   InternetCloseHandle(hInternet);	
   InternetCloseHandle(hSession);	
   
   if(StringLen(str) < 0.5*len) {
      Alert("Error reading data from: " + URL);
      Alert(str);
      errorFlag = true;
      return("111111111111111111111111111111111111111111111111111111111111111111");
   }
   
   return(str);
}
//+------------------------------------------------------------------+
// returns random int 0 -> 255
int RndChar() {
   
   static int i = 0;
   static string rndStr = "";
   static int rndStrLen = 0;   
   
   int ret;
   
   if(i >= rndStrLen-17) {
      rndStr = GetRndStr(5000, false);
      rndStrLen = StringLen(rndStr);
      i = 0;
   }
   
   ret = 0;
   
   ret |= (StringGetChar(rndStr, i + 0) - '0') << 0;     
   ret |= (StringGetChar(rndStr, i + 2) - '0') << 1;   
   ret |= (StringGetChar(rndStr, i + 4) - '0') << 2;   
   ret |= (StringGetChar(rndStr, i + 6) - '0') << 3;         
   ret |= (StringGetChar(rndStr, i + 8) - '0') << 4;      
   ret |= (StringGetChar(rndStr, i + 10) - '0') << 5;        
   ret |= (StringGetChar(rndStr, i + 12) - '0') << 6;   
   ret |= (StringGetChar(rndStr, i + 14) - '0') << 7;            
      
   i += 8;
   
   return(ret);
}
//+------------------------------------------------------------------+
// returns random bit
bool RndBit() {
   
   static int i = 0;
   static string rndStr = "";
   static int rndStrLen = 0;
   
   if(i >= rndStrLen) {
      i = 0;
      rndStr = GetRndStr(5000);
      rndStrLen = StringLen(rndStr);
   }
   
   if(StringGetChar(rndStr, i) == '1') {
      i += 2;
      return(true);
   }
   else {
      i += 2;
      return(false);   
   }
   
   return(false);   
}
//+------------------------------------------------------------------+
// Return log normal random variable as % of mean. Input random nr: 0.0 -> 1.0
double LogNormal(double r) {

   double x;
   int sign;
   
   sign = MathRound(r*10.0);
   sign = 1 - 2*(sign & 0x0001);
   
   x = MathExp(sign*MathSqrt(MathLog(1.0/r)));
   
   return(x);
}
//+------------------------------------------------------------------+

