/*********************************************************************
 * Copyright (c) 2005 The MetaStock Forum Crew.  All rights reserved.	
 * Redistribution and use in source and binary forms, with or without	
 * modification, are permitted provided that the following conditions	
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. Redistributions of any form whatsoever must retain the following
 *    acknowledgment:
 *    "This product includes software developed by MetaStock Forum Crew
 *    (http://forum.equis.com)."
 *
 * THIS SOFTWARE IS PROVIDED BY THE METASTOCK FORUM CREW "AS IS" AND ANY
 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE METASTOCK FORUM CREW OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 */
//------------------------------------------------------------------------
//Do not touch any of this paragraph / INCLUDES
//------------------------------------------------------------------------
	#include <string.h>
	#include <stdlib.h>
	#include <math.h>
	#include <float.h>
	#include "MSXStruc.h"
	#include "msfl.h"
	#include <ctime> // For Random Function
	#include <fstream> //For GlobalVar Function
	#ifdef __cplusplus
	extern "C" {
	#endif
//------------------------------------------------------------------------
//Do not touch any of this paragraph / LOAD-UNLOAD
//------------------------------------------------------------------------
BOOL WINAPI DllMain		(  HANDLE a_hModule,
                           DWORD  a_fdwReason,
                           LPVOID a_lpReserved     )
{BOOL   l_bRtrn = TRUE; 
switch (a_fdwReason)
		{
		case DLL_PROCESS_ATTACH:
		break;
		case DLL_PROCESS_DETACH:
		break;
		default:
		break;
		}
return l_bRtrn;}
//------------------------------------------------------------------------

//********************* MSXInfo - Copyright Info**************************
//
//		You need to change the number of functions available here
//
//		 1) Latch				Patrick Nouvion
//		 2) DateRange			Patrick Nouvion / Updated by Wabbit
//		 3) VarRef				Patrick Nouvion
//		 4) VarHHV				Patrick Nouvion
//		 5) VarLLV				Patrick Nouvion
//		 6) VarSUM				Patrick Nouvion
//		 7) VarHHVBARS			Patrick Nouvion
//		 8) VarLLVBARS			Patrick Nouvion
//		 9) VarMOV				Patrick Nouvion
//		10) VarRSI				Patrick Nouvion
//		11) VarMOM				Patrick Nouvion
//		12) VarCMO				Patrick Nouvion
//		13) CustomIndex			Patrick Nouvion
//		14) TD Combo			Patrick Nouvion
//		15) Custom SAR			Patrick Nouvion
//		16) Random				Patrick Nouvion
//		17) GlobalVar			Patrick Nouvion
//-------------------------------------------------------------------------------------------------------

//-------------------  COPYRIGHT INFO  ------------------------------------------------------------------
BOOL __stdcall MSXInfo (MSXDLLDef *a_psDLLDef)
{	strncpy (a_psDLLDef->szCopyright, "MetaStock Forum Crew 2005",
	sizeof(a_psDLLDef->szCopyright)-1);
	a_psDLLDef->iNFuncs = 17;//NUMBER OF FUNCTIONS MAKE SURE TO CHANGE THIS NUMBER WHEN ADDING A FUNCTION							
	a_psDLLDef->iVersion = MSX_VERSION;
	return MSX_SUCCESS;}
//------------------------------------------------------------------------

//***************** MSXNthFunction - Function Info************************
//
//You need to change the function name and its description here
//
//
// Case  0 = Function 1  = Latch
// Case  1 = Function 2  = DateRange
// Case  2 = function 3  = VarRef
// Case  3 = function 4  = VarHHV
// Case  4 = function 5  = VarLLV
// Case  5 = function 6  = VarSUM
// Case  6 = function 7  = VarHHVBARS
// Case  7 = function 8  = VarLLVBARS
// Case  8 = function 9  = VarMOV
// Case  9 = function 10 = VarRSI
// Case 10 = function 11 = VarMOM
// Case 11 = function 12 = VarCMO
// Case 12 = function 13 = CustomIndex
// Case 13 = function 14 = TDCOMBO
// Case 14 = function 15 = CSAR
// Case 15 = function 16 = Random
// Case 16 = function 17 = GlobalVar
//
//------------------------------------------------------------------------
BOOL __stdcall MSXNthFunction (int a_iNthFunc, MSXFuncDef *a_psFuncDef)
{
	int l_bRtrn = MSX_SUCCESS;
	switch (a_iNthFunc) {
	case 0: 
		strcpy (a_psFuncDef->szFunctionName, "Latch");									//Function Name
		strcpy (a_psFuncDef->szFunctionDescription, "Latch Function");					//Function Desc
		a_psFuncDef->iNArguments =4;													// # of Arguments
		break;
	case 1:
		strcpy (a_psFuncDef->szFunctionName, "DateRange");								//Function Name
		strcpy (a_psFuncDef->szFunctionDescription, "Is true only between the range");	//Function Desc
		a_psFuncDef->iNArguments = 2;													// # of Arguments
		break;
	case 2:
		strcpy (a_psFuncDef->szFunctionName, "VarREF");									//Function Name
		strcpy (a_psFuncDef->szFunctionDescription, " Variable Ref Function");			//Function Desc
		a_psFuncDef->iNArguments = 2;													// # of Arguments				
		break;
	case 3:
		strcpy (a_psFuncDef->szFunctionName, "VarHHV");									//Function Name
		strcpy (a_psFuncDef->szFunctionDescription, " Variable HHV Function");			//Function Desc
		a_psFuncDef->iNArguments = 2;													// # of Arguments		
		break;
	case 4:
		strcpy (a_psFuncDef->szFunctionName, "VarLLV");									//Function Name
		strcpy (a_psFuncDef->szFunctionDescription, " Variable LLV Function");			//Function Desc
		a_psFuncDef->iNArguments = 2;													// # of Arguments
		break;
	case 5:
		strcpy (a_psFuncDef->szFunctionName, "VarSUM");									//Function Name
		strcpy (a_psFuncDef->szFunctionDescription, " Variable SUM Function");			//Function Desc
		a_psFuncDef->iNArguments = 2;													//# of Arguments
		break;
	case 6:
		strcpy (a_psFuncDef->szFunctionName, "VarHHVBARS");								//Function Name
		strcpy (a_psFuncDef->szFunctionDescription, " Variable HHVBARS Function");		//Function Desc
		a_psFuncDef->iNArguments = 2;													//# of Arguments
		break;
	case 7:
		strcpy (a_psFuncDef->szFunctionName, "VarLLVBARS");									//Function Name
		strcpy (a_psFuncDef->szFunctionDescription, " Variable LLVBARS Function");			//Function Desc
		a_psFuncDef->iNArguments = 2;														//# of Arguments
		break;
	case 8:
		strcpy (a_psFuncDef->szFunctionName, "VarMOV");									//Function Name
		strcpy (a_psFuncDef->szFunctionDescription, " Variable MA Function");			//Function Desc
		a_psFuncDef->iNArguments = 3;													//# of Arguments
		break;
	case 9:
		strcpy (a_psFuncDef->szFunctionName, "VarRSI");									//Function Name
		strcpy (a_psFuncDef->szFunctionDescription, " Variable RSI Function");			//Function Desc
		a_psFuncDef->iNArguments = 2;													//# of Arguments
		break;
	case 10:
		strcpy (a_psFuncDef->szFunctionName, "VarMOM");										//Function Name
		strcpy (a_psFuncDef->szFunctionDescription, " Variable MOMENTUM Function");			//Function Desc
		a_psFuncDef->iNArguments = 2;														//# of Arguments
		break;
	case 11:
		strcpy (a_psFuncDef->szFunctionName, "VarCMO");									//Function Name
		strcpy (a_psFuncDef->szFunctionDescription, " Variable CMO Function");		//Function Desc
		a_psFuncDef->iNArguments = 2;														//# of Arguments
		break;
	case 12:
		strcpy (a_psFuncDef->szFunctionName, "CustomIndex");								//Function Name
		strcpy (a_psFuncDef->szFunctionDescription, "Custom Index");				//Function Desc
		a_psFuncDef->iNArguments =3;														//# of Arguments
		break;
	case 13:
		strcpy (a_psFuncDef->szFunctionName, "TDCOMBO");								//Function Name
		strcpy (a_psFuncDef->szFunctionDescription, "TD COMBO");   				//Function Desc
		a_psFuncDef->iNArguments = 0;														//# of Arguments
		break;
	case 14: 
		strcpy (a_psFuncDef->szFunctionName, "CSAR");									//Function Name
		strcpy (a_psFuncDef->szFunctionDescription, "Custom SAR Indicator");			//Function Desc
		a_psFuncDef->iNArguments = 3;													// # of Arguments
		break;
	case 15: 
		strcpy (a_psFuncDef->szFunctionName, "Random");									//Function Name
		strcpy (a_psFuncDef->szFunctionDescription, "Random Value");			//Function Desc
		a_psFuncDef->iNArguments = 2;													// # of Arguments
		break;
	case 16: 
		strcpy (a_psFuncDef->szFunctionName, "GlobalVar");									//Function Name
		strcpy (a_psFuncDef->szFunctionDescription, "Global Variables");			//Function Desc
		a_psFuncDef->iNArguments = 0;													// # of Arguments
		break;
		//If I wanted to add a new function I would write
		//	case X:
		//		strcpy (a_psFuncDef->szFunctionName, "FunctionX");						//Function Name
		//		strcpy (a_psFuncDef->szFunctionDescription, "X Function");				//Function Desc
		//		a_psFuncDef->iNArguments = 0; // # of args in function					//# of Arguments
		//		break;

//----------------------DEFAULT RESULT - DO NOT CHANGE-------------------
//--------------------- This will help MSXTest find errors in your code--
		default:
		l_bRtrn = MSX_ERROR;
		break;
	}
	return l_bRtrn;
}
//------------------------------------------------------------------------

//***************MSXNthArg - Function Arguments Info**********************
//
// You need to change the number of arguments per functions available here
// You will also define these arguments
//
//------------------------------------------------------------------------
BOOL __stdcall MSXNthArg (int a_iNthFunc, 
						  int a_iNthArg,
                          MSXFuncArgDef *a_psFuncArgDef)
{
   BOOL l_bRtrn = MSX_SUCCESS;
   switch (a_iNthFunc) {
   case 0: // This refers to the Latch Function
		   switch (a_iNthArg) {
								case 0: // Latch 1st Argument
										a_psFuncArgDef->iArgType = MSXDataArray;
										strcpy (a_psFuncArgDef->szArgName, "LE");
								break;
								case 1: // Latch 2nd Argument
										a_psFuncArgDef->iArgType = MSXDataArray;
										strcpy (a_psFuncArgDef->szArgName, "LX");
								break;
								case 2: // Latch 3rd Argument
										a_psFuncArgDef->iArgType = MSXDataArray;
										strcpy (a_psFuncArgDef->szArgName, "SE");
								break;
								case 3: // Latch 4th Argument
										a_psFuncArgDef->iArgType = MSXDataArray;
										strcpy (a_psFuncArgDef->szArgName, "SX");
								break;
								default:
								l_bRtrn = MSX_ERROR;
								break;
		   }
		   break;
			case 1: // This refers to the Date Range Function
		    switch (a_iNthArg) {
								case 0: // FirstDate
										a_psFuncArgDef->iArgType = MSXDataArray;
										strcpy (a_psFuncArgDef->szArgName, "FirstDate");
								break;
								case 1: // LastDate
										a_psFuncArgDef->iArgType = MSXDataArray;
										strcpy (a_psFuncArgDef->szArgName, "LastDate");
								break;
								default:
								l_bRtrn = MSX_ERROR;
								break;
			}
			break;
			case 2: // This refers to the VarREF Function
		    switch (a_iNthArg) {
								case 0: // VarVal
										a_psFuncArgDef->iArgType = MSXDataArray;
										strcpy (a_psFuncArgDef->szArgName, "Data Array");
								break;
								case 1: // VarPer
										a_psFuncArgDef->iArgType = MSXDataArray;
										strcpy (a_psFuncArgDef->szArgName, "Variable Period");
								break;
								default:
								l_bRtrn = MSX_ERROR;
								break;
			}
		  break;
		  case 3: // This refers to the VarHHV Function
		    switch (a_iNthArg) {
								case 0: // VarVal
										a_psFuncArgDef->iArgType = MSXDataArray;
										strcpy (a_psFuncArgDef->szArgName, "Data Array");
								break;
								case 1: // VarPer
										a_psFuncArgDef->iArgType = MSXDataArray;
										strcpy (a_psFuncArgDef->szArgName, "Variable Period");
								break;
								default:
								l_bRtrn = MSX_ERROR;
								break;
			}
		  break;
		  case 4: // This refers to the VarLLV Function
		    switch (a_iNthArg) {
								case 0: // VarVal
										a_psFuncArgDef->iArgType = MSXDataArray;
										strcpy (a_psFuncArgDef->szArgName, "Data Array");
								break;
								case 1: // VarPer
										a_psFuncArgDef->iArgType = MSXDataArray;
										strcpy (a_psFuncArgDef->szArgName, "Variable Period");
								break;
								default:
								l_bRtrn = MSX_ERROR;
								break;
			}
		 break;
		 case 5: // This refers to the VarSUM Function
		  switch (a_iNthArg) {
							case 0: // VarVal
									a_psFuncArgDef->iArgType = MSXDataArray;
									strcpy (a_psFuncArgDef->szArgName, "Data Array");
							break;
							case 1: // VarPer
									a_psFuncArgDef->iArgType = MSXDataArray;
									strcpy (a_psFuncArgDef->szArgName, "Variable Period");
							break;
							default:
							l_bRtrn = MSX_ERROR;
							break;
		}
		  break;
		   case 6: // This refers to the VarHHVBARS Function
		  switch (a_iNthArg) {
							case 0: // VarVal
									a_psFuncArgDef->iArgType = MSXDataArray;
									strcpy (a_psFuncArgDef->szArgName, "Data Array");
							break;
							case 1: // VarPer
									a_psFuncArgDef->iArgType = MSXDataArray;
									strcpy (a_psFuncArgDef->szArgName, "Variable Period");
							break;
							default:
							l_bRtrn = MSX_ERROR;
							break;
		}
		   break;
		   case 7: // This refers to the VarLLVBARS Function
		  switch (a_iNthArg) {
							case 0: // VarVal
									a_psFuncArgDef->iArgType = MSXDataArray;
									strcpy (a_psFuncArgDef->szArgName, "Data Array");
							break;
							case 1: // VarPer
									a_psFuncArgDef->iArgType = MSXDataArray;
									strcpy (a_psFuncArgDef->szArgName, "Variable Period");
							break;
							default:
							l_bRtrn = MSX_ERROR;
							break;
		}
		  break;
		  case 8: // This refers to the VarMOV Function
		  switch (a_iNthArg) {
							case 0: // VarVal
									a_psFuncArgDef->iArgType = MSXDataArray;
									strcpy (a_psFuncArgDef->szArgName, "Data Array");
							break;
							case 1: // VarPer
									a_psFuncArgDef->iArgType = MSXDataArray;
									strcpy (a_psFuncArgDef->szArgName, "Variable Period");
							break;
							case 2:
									a_psFuncArgDef->iArgType = MSXCustom; // CustomType
									a_psFuncArgDef->iNCustomStrings = 8; 
									strcpy (a_psFuncArgDef->szArgName, "Method");
							break;
							default:
							l_bRtrn = MSX_ERROR;
							break;
		}
		 break;
		 case 9: // This refers to the VarRSI Function
		  switch (a_iNthArg) {
							case 0: // VarVal
									a_psFuncArgDef->iArgType = MSXDataArray;
									strcpy (a_psFuncArgDef->szArgName, "Data Array");
							break;
							case 1: // VarPer
									a_psFuncArgDef->iArgType = MSXDataArray;
									strcpy (a_psFuncArgDef->szArgName, "Variable Period");
							break;
							default:
							l_bRtrn = MSX_ERROR;
							break;
		}
		break;
		case 10: // This refers to the VarMOM Function
		  switch (a_iNthArg) {
							case 0: // VarVal
									a_psFuncArgDef->iArgType = MSXDataArray;
									strcpy (a_psFuncArgDef->szArgName, "Data Array");
							break;
							case 1: // VarPer
									a_psFuncArgDef->iArgType = MSXDataArray;
									strcpy (a_psFuncArgDef->szArgName, "Variable Period");
							break;
							default:
							l_bRtrn = MSX_ERROR;
							break;
		}
		 break;
		 case 11: // This refers to the VarCMO Function
		  switch (a_iNthArg) {
							case 0: // VarVal
									a_psFuncArgDef->iArgType = MSXDataArray;
									strcpy (a_psFuncArgDef->szArgName, "Data Array");
							break;
							case 1: // VarPer
									a_psFuncArgDef->iArgType = MSXDataArray;
									strcpy (a_psFuncArgDef->szArgName, "Variable Period");
							break;
							default:
							l_bRtrn = MSX_ERROR;
							break;
		}
	   break;
		 case 12: // This refers to the CustomIndex Function
		  switch (a_iNthArg) {
							case 0: // Path
									a_psFuncArgDef->iArgType = MSXString;
									strcpy (a_psFuncArgDef->szArgName, "Path");
							break;
							case 1:
									a_psFuncArgDef->iArgType = MSXCustom; // CustomType
									a_psFuncArgDef->iNCustomStrings = 10; 
									strcpy (a_psFuncArgDef->szArgName, "Price Array");
							break;
							case 2:
									a_psFuncArgDef->iArgType = MSXCustom; // CustomType
									a_psFuncArgDef->iNCustomStrings = 4; 
									strcpy (a_psFuncArgDef->szArgName, "Method");
							break;
							default:
							l_bRtrn = MSX_ERROR;
							break;
		}
		  break;
		  case 14: //This refers to the CSAR function
				switch (a_iNthArg) {
				case 0:
				a_psFuncArgDef->iArgType = MSXDataArray;
				strcpy (a_psFuncArgDef->szArgName, "Data Array");
				break;
				case 1:
				a_psFuncArgDef->iArgType = MSXDataArray; // Numeric
				strcpy (a_psFuncArgDef->szArgName, "Step");
				break;
				case 2:
				a_psFuncArgDef->iArgType = MSXDataArray; // Numeric
				strcpy (a_psFuncArgDef->szArgName, "Maximum");
				break;
				default:
				l_bRtrn = MSX_ERROR;
				break;
				}
			break;
			 case 15: //This refers to the CSAR function
				switch (a_iNthArg) {
				case 0:
				a_psFuncArgDef->iArgType = MSXDataArray; // Numeric
				strcpy (a_psFuncArgDef->szArgName, "Min");
				break;
				case 1:
				a_psFuncArgDef->iArgType = MSXDataArray; // Numeric
				strcpy (a_psFuncArgDef->szArgName, "Max");
				break;
				default:
				l_bRtrn = MSX_ERROR;
				break;
				}
			break;
		  default:
		  l_bRtrn = MSX_ERROR;
		  break;
   }
   return l_bRtrn;
 }
//****************CUSTOM STRING DECLARATION*******************************
BOOL __stdcall MSXNthCustomString (int a_iNthFunc, 
								   int a_iNthArg,
                                   int a_iNthString, 
								   MSXFuncCustomString *a_psCustomString)
{
  BOOL l_bRtrn = MSX_SUCCESS;
  a_psCustomString->szString[0] = '\0';
  a_psCustomString->iID = -1;
  typedef struct {
    char *szString;
    int  iID;
  } LocalStringElement;
  
  LocalStringElement l_sTheStrings[] = {
  {"Simple",0},{"S",0},{"Triangular",1},{"T",1},{"Weighted",2},{"W",2},{"Exponential",3},{"E",3}
  };
  
  LocalStringElement CustomIndexPrice[] = {
		{"Open", 0}, {"O", 0},
		{"High", 1}, {"H", 1},
		{"Low", 2}, {"L", 2},
		{"Close", 3}, {"C", 3},
		{"Volume", 4}, {"V", 4}
	};

  LocalStringElement CustomIndexMethod[] = {
		{"Summation", 0}, {"Sum", 0},
		{"Index", 1}, {"I", 1}
  };

  switch (a_iNthFunc) {
  case 8:
						switch (a_iNthArg) {
						case 2:
						if(a_iNthString >= 0 && a_iNthString < 11) {
							strncpy (a_psCustomString->szString, l_sTheStrings[a_iNthString].szString,
									sizeof(a_psCustomString->szString)-1);
							a_psCustomString->iID = l_sTheStrings[a_iNthString].iID;
						}
						break;
						default:
						l_bRtrn = MSX_ERROR;
						break;
    }
   	break;
	case 12:
						switch (a_iNthArg) {
						case 1:
						if(a_iNthString >= 0 && a_iNthString < 11) {
							strncpy (a_psCustomString->szString, CustomIndexPrice[a_iNthString].szString,
									sizeof(a_psCustomString->szString)-1);
							a_psCustomString->iID = CustomIndexPrice[a_iNthString].iID;
						}
						break;
						case 2:
						if(a_iNthString >= 0 && a_iNthString < 5) {
							strncpy (a_psCustomString->szString, CustomIndexMethod[a_iNthString].szString,
									sizeof(a_psCustomString->szString)-1);
							a_psCustomString->iID = CustomIndexMethod[a_iNthString].iID;
						}
						break;
						default:
						l_bRtrn = MSX_ERROR;
						break;
    }
	break;
    default:
    l_bRtrn = MSX_ERROR;
    break;
  }
  return l_bRtrn;
}
// ****************DO NOT CHANGE ANYTHING HERE*****************************
// This local utility function is used to help ensure that no overflows
//   or underflows will occur during calcuations.  The MSXTest program
//   Stress Test function will call your DLL with a wide range of values,
//   including positive and negative values of FLT_MAX and FLT_MIN.
// Perform all intermediate calculations using doubles and then force the
//   results into the range of a float.
// Locally defined macros are used to avoid compiler definition differences
// ************************************************************************
#define MSXMax(a,b) (((a) > (b)) ? (a) : (b))
#define MSXMin(a,b) (((a) < (b)) ? (a) : (b))
double ForceFloatRange (double a_lfDbl)
{
	if (a_lfDbl > 0.0)
	{
		a_lfDbl = MSXMin (a_lfDbl, double(FLT_MAX)); // make sure positive number <= FLT_MAX
		a_lfDbl = MSXMax (a_lfDbl, double(FLT_MIN)); // make sure pos number >= FLT_MIN
	}
	else
	{
		if (a_lfDbl < 0.0)
		{
			a_lfDbl = MSXMax (a_lfDbl, double(-FLT_MAX)); // make sure neg number >= -FLT_MAX
			a_lfDbl = MSXMin (a_lfDbl, double(-FLT_MIN)); // make sure neg number <= -FLT_MIN
		}
	}
	return a_lfDbl;
}
//********************************START LATCH FUNCTION **********************
BOOL __stdcall Latch	 (const MSXDataRec *a_psDataRec,
                          const MSXDataInfoRecArgsArray *a_psDataInfoArgs,
                          const MSXNumericArgsArray *a_psNumericArgs,
                          const MSXStringArgsArray *a_psStringArgs,
                          const MSXCustomArgsArray *a_psCustomArgs,
                          MSXResultRec *a_psResultRec)
{
BOOL   l_bRtrn = MSX_SUCCESS;
int i = 0;
int MaxRecords = a_psDataRec->sClose.iLastValid;
const MSXDataInfoRec *l_psLE; l_psLE = a_psDataInfoArgs->psDataInfoRecs[0];
const MSXDataInfoRec *l_psLX; l_psLX = a_psDataInfoArgs->psDataInfoRecs[1];
const MSXDataInfoRec *l_psSE; l_psSE = a_psDataInfoArgs->psDataInfoRecs[2];
const MSXDataInfoRec *l_psSX; l_psSX = a_psDataInfoArgs->psDataInfoRecs[3];
for (i=0; i<=MaxRecords; i++)
{	if(i==0){	a_psResultRec->psResultArray->pfValue[i] =   0;}
	else if(	l_psLE->pfValue[i] == 1){a_psResultRec->psResultArray->pfValue[i] =   1;}
	else if(	l_psSE->pfValue[i] == 1){a_psResultRec->psResultArray->pfValue[i] =  -1;}
	else if((	l_psLX->pfValue[i] == 1 && a_psResultRec->psResultArray->pfValue[i - 1]== 1)
			||  l_psSX->pfValue[i] == 1 && a_psResultRec->psResultArray->pfValue[i - 1]==-1){
				a_psResultRec->psResultArray->pfValue[i] =  0;}
	else {		a_psResultRec->psResultArray->pfValue[i] = a_psResultRec->psResultArray->pfValue[i - 1];}
}
 if (l_bRtrn != MSX_SUCCESS) { // only for serious errors...
    a_psResultRec->psResultArray->iFirstValid = 0;
    a_psResultRec->psResultArray->iLastValid = -1;
 }
return l_bRtrn;
}
//*********************************END LATCH FUNCTION**********************************************
//*********************************START DATE RANGE FUNCTION***************************************
BOOL __stdcall DateRange ( const MSXDataRec *a_psDataRec,
const MSXDataInfoRecArgsArray *a_psDataInfoArgs,
const MSXNumericArgsArray *a_psNumericArgs,
const MSXStringArgsArray *a_psStringArgs,
const MSXCustomArgsArray *a_psCustomArgs,
MSXResultRec *a_psResultRec)
{
BOOL l_bRtrn = MSX_SUCCESS;
int i=0;
int MaxRecords = a_psDataRec->sClose.iLastValid;
MSXDateTime *psDate = a_psDataRec->psDate;
int IntDate = 0;
const MSXDataInfoRec *l_StartDate; l_StartDate = a_psDataInfoArgs->psDataInfoRecs[0];
const MSXDataInfoRec *l_EndDate; l_EndDate = a_psDataInfoArgs->psDataInfoRecs[1];

for(i=0; i<=MaxRecords; i++)
{
IntDate = psDate[i].lDate;
if(l_StartDate->pfValue[i]==0 && IntDate <= l_EndDate->pfValue[i])
{a_psResultRec->psResultArray->pfValue[i]= 1;}
else if(l_EndDate->pfValue[i]==0 && IntDate >= l_StartDate->pfValue[i])
{a_psResultRec->psResultArray->pfValue[i]= 1;}
else if(IntDate >= l_StartDate->pfValue[i] && IntDate <= l_EndDate->pfValue[i])
{a_psResultRec->psResultArray->pfValue[i]= 1;} 
}
// only for serious errors...
if (l_bRtrn != MSX_SUCCESS)
{
a_psResultRec->psResultArray->iFirstValid = 0;
a_psResultRec->psResultArray->iLastValid = -1;
}
return l_bRtrn;
}
//*********************************END DATE RANGE FUNCTION****************************************** 

//*********************************START VARREF FUNCTION********************************************
BOOL __stdcall VarREF    	   (const MSXDataRec *a_psDataRec,
								const MSXDataInfoRecArgsArray *a_psDataInfoArgs,
								const MSXNumericArgsArray *a_psNumericArgs,
								const MSXStringArgsArray *a_psStringArgs,
								const MSXCustomArgsArray *a_psCustomArgs,
								MSXResultRec *a_psResultRec)
{
BOOL		l_bRtrn = MSX_SUCCESS;
const		MSXDataInfoRec *l_VarVal; l_VarVal = a_psDataInfoArgs->psDataInfoRecs[0];
const		MSXDataInfoRec *l_VarPer; l_VarPer = a_psDataInfoArgs->psDataInfoRecs[1];
int			MinRecords = a_psResultRec->psResultArray->iFirstValid;
int			MaxRecords = a_psResultRec->psResultArray->iLastValid;
int			i = 0;
for (int i = MinRecords; i <= MaxRecords; i++ ){
			int J = static_cast<int>(l_VarPer->pfValue[i]);
			if( J >= i){J = 0;}
			a_psResultRec->psResultArray->pfValue[i] = l_VarVal->pfValue[i-J];
}
if (l_bRtrn != MSX_SUCCESS) { // only for serious errors...
    a_psResultRec->psResultArray->iFirstValid = 0;
    a_psResultRec->psResultArray->iLastValid = -1;
}
return l_bRtrn;
}
//*********************************END VARREF FUNCTION*******************************************

//*********************************START VARHHV FUNCTION*****************************************
BOOL __stdcall VarHHV    	   (const MSXDataRec *a_psDataRec,
								const MSXDataInfoRecArgsArray *a_psDataInfoArgs,
								const MSXNumericArgsArray *a_psNumericArgs,
								const MSXStringArgsArray *a_psStringArgs,
								const MSXCustomArgsArray *a_psCustomArgs,
								MSXResultRec *a_psResultRec)

{	BOOL   l_bRtrn = MSX_SUCCESS;
	const MSXDataInfoRec *l_VarVal; l_VarVal = a_psDataInfoArgs->psDataInfoRecs[0];
	const MSXDataInfoRec *l_VarPer; l_VarPer = a_psDataInfoArgs->psDataInfoRecs[1];
	int MinRecords = a_psResultRec->psResultArray->iFirstValid;
	int MaxRecords = a_psResultRec->psResultArray->iLastValid;
	int i = 0;
	float MaxValue = 0;
for (i = MinRecords; i <= MaxRecords; i++ )
{ int j = abs(static_cast<int>(l_VarPer->pfValue[i])); //Convert variable period to int
if( j > i) {j=i;}									   //If variable int is greater than current bar count use current bar count  
float MaxValue = 0;
int t=0;
for(t=0;t<j;t++){
	if(t == 0)							{ MaxValue = l_VarVal->pfValue[i];}
	if(MaxValue<l_VarVal->pfValue[i-t])	{ MaxValue = l_VarVal->pfValue[i-t];}
}
a_psResultRec->psResultArray->pfValue[i] = MaxValue;
}
if (l_bRtrn != MSX_SUCCESS) { // only for serious errors...
    a_psResultRec->psResultArray->iFirstValid = 0;
    a_psResultRec->psResultArray->iLastValid = -1;
  }
return l_bRtrn;
}
//*********************************END VARHHV FUNCTION*****************************************

//*********************************START VARLLV FUNCTION*****************************************
BOOL __stdcall VarLLV    	   (const MSXDataRec *a_psDataRec,
								const MSXDataInfoRecArgsArray *a_psDataInfoArgs,
								const MSXNumericArgsArray *a_psNumericArgs,
								const MSXStringArgsArray *a_psStringArgs,
								const MSXCustomArgsArray *a_psCustomArgs,
								MSXResultRec *a_psResultRec)

{	BOOL   l_bRtrn = MSX_SUCCESS;
	const MSXDataInfoRec *l_VarVal; l_VarVal = a_psDataInfoArgs->psDataInfoRecs[0];
	const MSXDataInfoRec *l_VarPer; l_VarPer = a_psDataInfoArgs->psDataInfoRecs[1];
	int MinRecords = a_psResultRec->psResultArray->iFirstValid;
	int MaxRecords = a_psResultRec->psResultArray->iLastValid;
	int i = 0;
	float MinValue = 0;
for (i = MinRecords; i <= MaxRecords; i++ )
{ int j = abs(static_cast<int>(l_VarPer->pfValue[i])); //Convert variable period to int
if( j > i) {j=i;}									   //If variable int is greater than current bar count use current bar count  
float MinValue = 0;
int t=0;
for(t=0;t<j;t++){
	if(t == 0)					{ MinValue = l_VarVal->pfValue[i];}
	if(MinValue>l_VarVal->pfValue[i-t])	{ MinValue = l_VarVal->pfValue[i-t];}
}
a_psResultRec->psResultArray->pfValue[i] = MinValue;
}
if (l_bRtrn != MSX_SUCCESS) { // only for serious errors...
    a_psResultRec->psResultArray->iFirstValid = 0;
    a_psResultRec->psResultArray->iLastValid = -1;
  }
return l_bRtrn;
}
//*********************************END VARLLV FUNCTION*****************************************

//*********************************START VARSUM FUNCTION***************************************
BOOL __stdcall VarSUM    	   (const MSXDataRec *a_psDataRec,
								const MSXDataInfoRecArgsArray *a_psDataInfoArgs,
								const MSXNumericArgsArray *a_psNumericArgs,
								const MSXStringArgsArray *a_psStringArgs,
								const MSXCustomArgsArray *a_psCustomArgs,
								MSXResultRec *a_psResultRec)

{	BOOL   l_bRtrn = MSX_SUCCESS;
	const MSXDataInfoRec *l_VarVal; l_VarVal = a_psDataInfoArgs->psDataInfoRecs[0];
	const MSXDataInfoRec *l_VarPer; l_VarPer = a_psDataInfoArgs->psDataInfoRecs[1];
	int MaxRecords = a_psResultRec->psResultArray->iLastValid;
	int i = 0;
	float SumValue = 0;
	for (i = static_cast<int>(l_VarPer->pfValue[1]); i <= MaxRecords; i++ )
{ int j = abs(static_cast<int>(l_VarPer->pfValue[i])); //Convert variable period to int
if( j > i) {j=0;}									   //If variable int is greater than current bar count use current bar count  
int t=0;
for(t=0;t<j;t++){
	if(t == 0)	{ SumValue = l_VarVal->pfValue[i];}
	if(t != 0)	{ SumValue += l_VarVal->pfValue[i-t];}
}
a_psResultRec->psResultArray->pfValue[i] = SumValue;
}
if (l_bRtrn != MSX_SUCCESS) { // only for serious errors...
    a_psResultRec->psResultArray->iFirstValid = 0;
    a_psResultRec->psResultArray->iLastValid = -1;
  }
return l_bRtrn;
}
//*********************************END VARSUM FUNCTION*****************************************

//*********************************START VARHHVBARS FUNCTION*****************************************
BOOL __stdcall VarHHVBARS  	   (const MSXDataRec *a_psDataRec,
								const MSXDataInfoRecArgsArray *a_psDataInfoArgs,
								const MSXNumericArgsArray *a_psNumericArgs,
								const MSXStringArgsArray *a_psStringArgs,
								const MSXCustomArgsArray *a_psCustomArgs,
								MSXResultRec *a_psResultRec)

{	BOOL   l_bRtrn = MSX_SUCCESS;
	const MSXDataInfoRec *l_VarVal; l_VarVal = a_psDataInfoArgs->psDataInfoRecs[0];
	const MSXDataInfoRec *l_VarPer; l_VarPer = a_psDataInfoArgs->psDataInfoRecs[1];
	int MinRecords = a_psResultRec->psResultArray->iFirstValid;
	int MaxRecords = a_psResultRec->psResultArray->iLastValid;
	int i = 0;
	float MaxValue = 0;
for (i = MinRecords; i <= MaxRecords; i++ )
{ int j = abs(static_cast<int>(l_VarPer->pfValue[i])); //Convert variable period to int
if( j > i || j < 1) {j=0;}									   //If variable int is greater than current bar count use current bar count  
float MaxValue = 0;
int t=0;
int counter = 0;
for(t=0;t<j;t++){
	if(t == 0)							{ MaxValue = l_VarVal->pfValue[i];	 counter = i;}
	if(MaxValue<l_VarVal->pfValue[i-t])	{ MaxValue = l_VarVal->pfValue[i-t]; counter = i - t;}
	}
a_psResultRec->psResultArray->pfValue[i] = static_cast<float>(i-counter);
}
if (l_bRtrn != MSX_SUCCESS) { // only for serious errors...
    a_psResultRec->psResultArray->iFirstValid = 0;
    a_psResultRec->psResultArray->iLastValid = -1;
  }
return l_bRtrn;
}
//*********************************END VARHHVBARS FUNCTION*****************************************

//*********************************START VARLLVBARS FUNCTION*****************************************
BOOL __stdcall VarLLVBARS  	   (const MSXDataRec *a_psDataRec,
								const MSXDataInfoRecArgsArray *a_psDataInfoArgs,
								const MSXNumericArgsArray *a_psNumericArgs,
								const MSXStringArgsArray *a_psStringArgs,
								const MSXCustomArgsArray *a_psCustomArgs,
								MSXResultRec *a_psResultRec)

{	BOOL   l_bRtrn = MSX_SUCCESS;
	const MSXDataInfoRec *l_VarVal; l_VarVal = a_psDataInfoArgs->psDataInfoRecs[0];
	const MSXDataInfoRec *l_VarPer; l_VarPer = a_psDataInfoArgs->psDataInfoRecs[1];
	int MinRecords = a_psResultRec->psResultArray->iFirstValid;
	int MaxRecords = a_psResultRec->psResultArray->iLastValid;
	int i = 0;
	float MinValue = 0;
for (i = MinRecords; i <= MaxRecords; i++ )
{ int j = abs(static_cast<int>(l_VarPer->pfValue[i])); //Convert variable period to int
if( j > i || j < 1) {j=0;}									   //If variable int is greater than current bar count use current bar count  
float MinValue = 0;
int t=0;
int counter = 0;
for(t=0;t<j;t++){
	if(t == 0)							{ MinValue = l_VarVal->pfValue[i];	 counter = i;}
	if(MinValue>l_VarVal->pfValue[i-t])	{ MinValue = l_VarVal->pfValue[i-t]; counter = i - t;}
	}
a_psResultRec->psResultArray->pfValue[i] = static_cast<float>(i-counter);
}
if (l_bRtrn != MSX_SUCCESS) { // only for serious errors...
    a_psResultRec->psResultArray->iFirstValid = 0;
	a_psResultRec->psResultArray->iLastValid = -1;
  }
return l_bRtrn;
}
//*********************************END VARLLVBARS FUNCTION*****************************************

//*********************************START VARMOV FUNCTION*******************************************
void MovingAverage (const MSXDataInfoRec *a_psSrc, MSXDataInfoRec *a_psRslt,
                   int a_iPeriod, BOOL a_bIsWeighted)
{
  int    l_iIndex = a_psSrc->iFirstValid;
  int    l_iMaxIndex = a_psSrc->iLastValid;
  double l_lfSum = 0.0;
  double l_lfDbl;
  float  l_fDivisor;
  int    i;

  if (a_bIsWeighted)
    l_fDivisor = float(a_iPeriod) * (float(a_iPeriod)+1.0f) / 2.0f; // sum of the digits formula
  else 
    l_fDivisor = float(a_iPeriod);
  l_fDivisor = float(ForceFloatRange (l_fDivisor));
  if (l_fDivisor == 0.0)
    l_fDivisor = 1.0f;
  while ((l_iIndex + a_iPeriod - 1) <= l_iMaxIndex) {
    l_lfSum = 0.0;
    for (i=0; i<a_iPeriod; i++) {
      if (a_bIsWeighted)
        l_lfSum += a_psSrc->pfValue[l_iIndex+i] * (i + 1.0f);
      else
        l_lfSum += a_psSrc->pfValue[l_iIndex+i];
    }
    l_lfSum = ForceFloatRange(l_lfSum);
    l_lfDbl = l_lfSum / l_fDivisor;
    l_lfDbl = ForceFloatRange(l_lfDbl);
    a_psRslt->pfValue[l_iIndex + a_iPeriod - 1] = float(l_lfDbl);
    l_iIndex++;
  }
  a_psRslt->iFirstValid = a_psSrc->iFirstValid + a_iPeriod - 1;
  a_psRslt->iLastValid = l_iMaxIndex;
}
void  ExponentialMovingAverage (const MSXDataInfoRec *a_psSrc,
                               MSXDataInfoRec *a_psRslt,
                               int a_iPeriod)
{
  int   l_iIndex = a_psSrc->iFirstValid;
  int   l_iMaxIndex = a_psSrc->iLastValid;
  double l_lfSum = 0.0;
  double l_lfDivisor;
  double l_lfExponent;
  int   i;

  if (a_iPeriod > 0 && ((l_iIndex + a_iPeriod - 1) <= l_iMaxIndex)) {
    l_lfExponent = ForceFloatRange(2.0 / (a_iPeriod+1));
    l_lfDivisor = double(a_iPeriod);
    // start with simple moving average;
    for (i=0; i<a_iPeriod; i++)
      l_lfSum += a_psSrc->pfValue[l_iIndex+i];
    l_lfSum = ForceFloatRange(l_lfSum);
    a_psRslt->pfValue[l_iIndex + a_iPeriod - 1] = float(ForceFloatRange(l_lfSum / l_lfDivisor));
    l_iIndex += a_iPeriod;
    while (l_iIndex <= l_iMaxIndex) {
      a_psRslt->pfValue[l_iIndex] = 
          float(ForceFloatRange((a_psSrc->pfValue[l_iIndex] - a_psRslt->pfValue[l_iIndex-1]) *
                           l_lfExponent + a_psRslt->pfValue[l_iIndex-1]));
      l_iIndex++;
    }
    a_psRslt->iFirstValid = a_psSrc->iFirstValid + a_iPeriod - 1;
    a_psRslt->iLastValid = l_iMaxIndex;
  }
  else {
    a_psRslt->iFirstValid = 0;
    a_psRslt->iLastValid = -1;
  }
}
BOOL __stdcall VarMOV (const MSXDataRec *a_psDataRec,
                      const MSXDataInfoRecArgsArray *a_psDataInfoArgs,
                      const MSXNumericArgsArray *a_psNumericArgs,
                      const MSXStringArgsArray *a_psStringArgs,
                      const MSXCustomArgsArray *a_psCustomArgs,
                      MSXResultRec *a_psResultRec)
{
  BOOL l_bRtrn = MSX_SUCCESS;
  const MSXDataInfoRec *l_psData;
  const MSXDataInfoRec *l_psVarPer;
  int                  l_iMethod;
  int                  l_iIndex;
  int                  l_iMaxIndex;
  l_psData = a_psDataInfoArgs->psDataInfoRecs[0];
  l_psVarPer = a_psDataInfoArgs->psDataInfoRecs[1];
  int l_iPeriod = 0;
  l_iMethod = a_psCustomArgs->iCustomIDs[0];
  l_iIndex = l_psData->iFirstValid;
  l_iMaxIndex = l_psData->iLastValid;
  int i = 0;
  for(i=0;i<=l_iMaxIndex;i++){
	  l_iPeriod = static_cast<int>(l_psVarPer->pfValue[i]);
	  if(l_iPeriod > i){l_iPeriod = i;}
      if (l_iPeriod > 0 && (l_iIndex + l_iPeriod - 1) <= l_iMaxIndex &&
		l_iIndex > 0 && l_iMaxIndex > 0 &&
		l_iIndex >= a_psDataRec->sClose.iFirstValid &&
		l_iMaxIndex <= a_psDataRec->sClose.iLastValid) {
      switch (l_iMethod) {
      case 0: // Simple
        MovingAverage (l_psData, a_psResultRec->psResultArray, l_iPeriod, FALSE);
        break;
      case 1: // Triangular
        {
          MSXDataInfoRec l_sTmpRec;
          l_sTmpRec.pfValue = new float[l_iMaxIndex+1];
          if (l_sTmpRec.pfValue) {
            l_iPeriod = (int)(((l_iPeriod+1.0)/2) + 0.5);
            MovingAverage (l_psData, &l_sTmpRec, l_iPeriod, FALSE);
            MovingAverage (&l_sTmpRec, a_psResultRec->psResultArray, l_iPeriod, FALSE);
            delete l_sTmpRec.pfValue;
          }
          else {
            a_psResultRec->psResultArray->iFirstValid = 0;
            a_psResultRec->psResultArray->iLastValid = -1;
          }
        }
        break;
      case 2: // Weighted
        MovingAverage (l_psData, a_psResultRec->psResultArray, l_iPeriod, TRUE);
        break;
      case 3: // Exponential
        ExponentialMovingAverage (l_psData, a_psResultRec->psResultArray, l_iPeriod);
        break;
      default:
        {
          // Somehow we got called with an invalid argument
          strncpy (a_psResultRec->szExtendedError, "Undefined method argument",
                   sizeof(a_psResultRec->szExtendedError)-1);
          l_bRtrn = MSX_ERROR; // report this as an error
        }
        break;
      }
    }
    else {
      a_psResultRec->psResultArray->iFirstValid = 0;
      a_psResultRec->psResultArray->iLastValid = -1;
    }
 if (l_bRtrn != MSX_SUCCESS) { // only for serious errors...
    a_psResultRec->psResultArray->iFirstValid = 0;
    a_psResultRec->psResultArray->iLastValid = -1;
 }}
  return l_bRtrn;
}
//*********************************END VARMOV FUNCTION*******************************************
BOOL __stdcall VarRSI   	   (const MSXDataRec *a_psDataRec,
								const MSXDataInfoRecArgsArray *a_psDataInfoArgs,
								const MSXNumericArgsArray *a_psNumericArgs,
								const MSXStringArgsArray *a_psStringArgs,
								const MSXCustomArgsArray *a_psCustomArgs,
								MSXResultRec *a_psResultRec)

{	BOOL   l_bRtrn = MSX_SUCCESS;
	const MSXDataInfoRec *l_VarVal; l_VarVal = a_psDataInfoArgs->psDataInfoRecs[0];
	const MSXDataInfoRec *l_VarPer; l_VarPer = a_psDataInfoArgs->psDataInfoRecs[1];
	int i;
	int periods;
    double UpChange  = 0.0;
	double DnChange  = 0.0;
    double UpAverage = 0.0; 
	double DnAverage = 0.0;
	for ( i = static_cast<int>(l_VarPer->pfValue[1]+1); i <=static_cast<int>(l_VarVal->iLastValid); i++ )
   {   periods = abs(static_cast<int>(l_VarPer->pfValue[i]));
	if(i<periods){periods=i;}
       UpChange = l_VarVal->pfValue[i]- l_VarVal->pfValue[i-1];
       DnChange = UpChange;
	   UpChange = l_VarVal->pfValue[i] - l_VarVal->pfValue[i - 1];
       DnChange = UpChange;
       if ( ( UpChange < 0.0 ) )
           UpChange = 0.0;
       if ( ( DnChange > 0.0 ) )
           DnChange = 0.0;
       else
           DnChange = fabs( DnChange );
	   if ( ( i <= periods + 1 ) )
       {
           UpAverage += UpChange;
           DnAverage += DnChange;
		   if ( ( i == periods + 1 ) )
           {
               UpAverage /= i;
               DnAverage /= i;
           }   /* if lp */
       }   /* if lp */
       else
       {
UpAverage =( ( UpAverage * ( periods - 1 ) ) + UpChange ) / max(periods,0.001);
DnAverage =( ( DnAverage * ( periods - 1 ) ) + DnChange ) / max(periods,0.001);
	   }
a_psResultRec->psResultArray->pfValue[i]  =	static_cast<float>(UpAverage/(max(abs(DnAverage),0.0001)));
a_psResultRec->psResultArray->pfValue[i]  = (100 - ((float)100 /((a_psResultRec->psResultArray->pfValue[i]) + (float)1.0)));
a_psResultRec->psResultArray->iFirstValid  = periods+1;
   }
return l_bRtrn;
}
//*********************************END VARRSI FUNCTION*******************************************

//*********************************START VARMOM FUNCTION*****************************************
BOOL __stdcall VarMOM	  	   (const MSXDataRec *a_psDataRec,
								const MSXDataInfoRecArgsArray *a_psDataInfoArgs,
								const MSXNumericArgsArray *a_psNumericArgs,
								const MSXStringArgsArray *a_psStringArgs,
								const MSXCustomArgsArray *a_psCustomArgs,
								MSXResultRec *a_psResultRec)

{	BOOL   l_bRtrn = MSX_SUCCESS;
	const MSXDataInfoRec *l_VarVal; l_VarVal = a_psDataInfoArgs->psDataInfoRecs[0];
	const MSXDataInfoRec *l_VarPer; l_VarPer = a_psDataInfoArgs->psDataInfoRecs[1];
	int MinRecords = a_psResultRec->psResultArray->iFirstValid;
	int MaxRecords = a_psResultRec->psResultArray->iLastValid;
    int i = 0;
	int periods = 0;
    for ( i = 1; i <= MaxRecords; i++ )
   {periods = abs(static_cast<int>(l_VarPer->pfValue[i]));
       if (i>periods)
       {
           if ( l_VarVal->pfValue[i-periods] != 0.0 )

 a_psResultRec->psResultArray->pfValue[i] = (float)( (l_VarVal->pfValue[i]/l_VarVal->pfValue[i-periods] ) * 100.0 );

		   else
 a_psResultRec->psResultArray->pfValue[i] = 0.0f;
       } 
       else
 a_psResultRec->psResultArray->pfValue[i] = 0.0f;
   } 
if (l_bRtrn != MSX_SUCCESS) { // only for serious errors...
    a_psResultRec->psResultArray->iFirstValid = 0;
    a_psResultRec->psResultArray->iLastValid = -1;
}
return l_bRtrn;
}
//*********************************END   VARMOM FUNCTION*****************************************

//*********************************START VARCMO FUNCTION*****************************************
BOOL __stdcall VarCMO	  	   (const MSXDataRec *a_psDataRec,
								const MSXDataInfoRecArgsArray *a_psDataInfoArgs,
								const MSXNumericArgsArray *a_psNumericArgs,
								const MSXStringArgsArray *a_psStringArgs,
								const MSXCustomArgsArray *a_psCustomArgs,
								MSXResultRec *a_psResultRec)

{	BOOL   l_bRtrn = MSX_SUCCESS;
	const MSXDataInfoRec *l_VarVal; l_VarVal = a_psDataInfoArgs->psDataInfoRecs[0];
	const MSXDataInfoRec *l_VarPer; l_VarPer = a_psDataInfoArgs->psDataInfoRecs[1];
	int MinRecords = a_psResultRec->psResultArray->iFirstValid;
	int MaxRecords = a_psResultRec->psResultArray->iLastValid;
    int i = 0;
	int periods = 0;
	float fSumUpDays   = 0.0F;
	float fSumDownDays = 0.0F;
for (i=MinRecords+1; i<= MaxRecords; i++ )
{periods = abs(static_cast<int>(l_VarPer->pfValue[i]));
if (l_VarVal->pfValue[i] > l_VarVal->pfValue[i-1])
			fSumUpDays += (l_VarVal->pfValue[i] - l_VarVal->pfValue[i-1]);
			else if (l_VarVal->pfValue[i] < l_VarVal->pfValue[i-1])
				fSumDownDays += (float)fabs(l_VarVal->pfValue[i] - l_VarVal->pfValue[i-1]);
if (i > (MinRecords + periods))
		{if (l_VarVal->pfValue[i-periods] > l_VarVal->pfValue[i - periods - 1])
			fSumUpDays -= (l_VarVal->pfValue[i-periods] - l_VarVal->pfValue[i-periods - 1]);
			else if (l_VarVal->pfValue[i-periods] < l_VarVal->pfValue[i-periods - 1])
				fSumDownDays -= (float)fabs(l_VarVal->pfValue[i-periods] - l_VarVal->pfValue[i-periods - 1]);
		}
		if (fSumUpDays + fSumDownDays)
			 a_psResultRec->psResultArray->pfValue[i] = 100.0F * (fSumUpDays - fSumDownDays)/(fSumUpDays + fSumDownDays);
		else
			 a_psResultRec->psResultArray->pfValue[i] = 0.0F;
}
if (l_bRtrn != MSX_SUCCESS) { // only for serious errors...
    a_psResultRec->psResultArray->iFirstValid = 0;
    a_psResultRec->psResultArray->iLastValid = -1;
}
return l_bRtrn;
}
//*********************************END VARCMO FUNCTION*****************************************

//*********************************START TD COMBO FUNCTION******************************************
BOOL __stdcall TDCOMBO   	   (const MSXDataRec *a_psDataRec,
								const MSXDataInfoRecArgsArray *a_psDataInfoArgs,
								const MSXNumericArgsArray *a_psNumericArgs,
								const MSXStringArgsArray *a_psStringArgs,
								const MSXCustomArgsArray *a_psCustomArgs,
								MSXResultRec *a_psResultRec)

{	BOOL   l_bRtrn = MSX_SUCCESS;
	int			MinRecords = a_psResultRec->psResultArray->iFirstValid;
	int			MaxRecords = a_psResultRec->psResultArray->iLastValid;
	int					           i = MinRecords;
	int					    SetupBuy = 0;
	int					   SetupSell = 0;
	int					  TDBuySetup = 0;
	int                  TDSellSetup = 0;
	int					BUYCOMBOCD = 0;
	int					SELLCOMBOCD = 0;

for(i=MinRecords; i<=MaxRecords;i++){
	float				CloseNow =  a_psDataRec->sClose.pfValue[i];
    float				CloseBack = a_psDataRec->sClose.pfValue[i-3];
	float				Low2 =  a_psDataRec->sLow.pfValue[i-1];
	float				High2 = a_psDataRec->sHigh.pfValue[i-1];

				     if( CloseNow < CloseBack){SetupBuy += 1; SetupSell = 0;}
				else if( CloseNow > CloseBack){SetupBuy = 0; SetupSell += 1;}

				     if(  SetupBuy >= 9) {TDBuySetup = 1; TDSellSetup = 0;}
				else if( SetupSell >= 9) {TDBuySetup = 0; TDSellSetup = 1;}

				     if(  TDBuySetup==1 && CloseNow > Low2)    {SELLCOMBOCD  = 0; BUYCOMBOCD += 1;}
				else if( TDSellSetup==1 && CloseNow < High2)	{SELLCOMBOCD += 1; BUYCOMBOCD  = 0;}

					 if(  BUYCOMBOCD == 13) {a_psResultRec->psResultArray->pfValue[i] =  1;}
				else if(  SELLCOMBOCD == 13) {a_psResultRec->psResultArray->pfValue[i] = -1;}
				else if( BUYCOMBOCD != 13 && SELLCOMBOCD != 13){a_psResultRec->psResultArray->pfValue[i]  = 0;}
}
return l_bRtrn;
}
//*********************************END TDCOMBO FUNCTION*******************************************

//******************************** START RANDOM FUNCTION ****************************************
BOOL __stdcall Random   	 (const MSXDataRec * a_psData,
                              const MSXDataInfoRecArgsArray *a_psDataInfoArgs,
							  const MSXNumericArgsArray *a_psNumericArgs,
							  const MSXStringArgsArray *a_psStringArgs,
							  const MSXCustomArgsArray *a_psCustomArgs,
							  MSXResultRec * psResult)
{
	BOOL   l_bRtrn = MSX_SUCCESS;
	const  MSXDataInfoRec *l_VarMin; l_VarMin = a_psDataInfoArgs->psDataInfoRecs[0];
	const  MSXDataInfoRec *l_VarMax; l_VarMax = a_psDataInfoArgs->psDataInfoRecs[1];
	int i = 0;
	int random_integer = 0;
	time_t seconds;
	time(&seconds);
	for(i=0;i<=a_psData->sClose.iLastValid;i++){
		srand((unsigned int) seconds);
		int range = (static_cast<int>(l_VarMax->pfValue[i])-static_cast<int>(l_VarMin->pfValue[i]))+1;
		random_integer = (rand()%range)+1;	
		psResult->psResultArray->pfValue[i] = static_cast<float>(random_integer);
	}
	return l_bRtrn;
}
//******************************** END RANDOM FUNCTION ****************************************

#ifdef __cplusplus
}
#endif