TRADE struct encourages precision loss

Posted By: pascalx

TRADE struct encourages precision loss - 09/03/17 18:59

Hello.

Can you please change the member types of struct TRADE from float to double? The precision loss is a problem.

Code:
typedef struct TRADE
{
	float	fEntryPrice;	// buy price, or premium without multiplicator
	float	fExitPrice;	// sell price per unit, without spread
	float fResult;		// current profit of the trade
	float	fEntryLimit;	// buy entry limit
	float	fProfitLimit;	// profit limit price
// ...
} TRADE;



Here is an actual example where the conversion to float and back causes an issue. It became apparent when I tried to abuse a double to transfer a pointer to a TMF.

Code:
int callback(double v)
{
	printf("ncallback v: %f", v); // v = 134550672.0
	return 0;
}

void run()
{
	if (Bar == StartBar)
	{
		enterLong(callback, 134550669.0);
	}
}

Posted By: firecrest

Re: TRADE struct encourages precision loss - 09/04/17 03:39

I think you point out a good point but is such precision needed in trading?
Posted By: pascalx

Re: TRADE struct encourages precision loss - 09/04/17 09:42

Yeah maybe float is just fine for most of the variables in that struct. I didn't think that through yet. I just ran into above practical issue, so I suggest to have another look.

double and float are not the same thing. double is 8 bytes and float is 4 bytes. double can present significantly more numbers than float. If there comes a precision loss depends on the intended use.

The only solid reason to use float over double here (afaik) is to decrease the amount of memory needed for 1 TRADE instance, effectively halving it. Depending on your strategy code you will have different amount of trades. So decreasing its memory footprint is generally appreciated, especially if the application keeps all opened and closed trades in memory.

Conversion to float will definitely break all code where you want to use the 8 bytes of a double as pure storage. A more elegant solution for this case would be to add a void* member to the TRADE struct reserved for user data. Since a TRADE struct does not seem to provide a unique ID, you also cannot accompany it with a map of trade user data.

What are these variables for? Are these free for the user? Maybe the comment is just misleading.
Code:
var	Skill[NUM_SKILLS];	// general purpose variables for TMF



For prices, please correct me if my test is wrong, we could check if the storage precision is a problem like so.
I assume a 5 digit price precision for this test.

Code:
void main()
{	
	float f1 = 0.0;
	float f2 = 0.0;
	double d1 = 0.0;
	double d2 = 0.0;
	int i;
	
	printf("nBusy...");
	
	for (i=0; i<0x7fffffff; ++i)
	{
		d1 += 0.00001;
		f1 = d1;
		d2 = f1;
		if (d1 != d2)
		{
			printf("nMismatch %.5f vs %.5f", d1, d2);
			break;
		}
	}
	
	printf("nDone.");
}



Result:

Quote:
Busy...
Mismatch 0.00007 vs 0.00007
Done.


Ok. There is a mismatch quite early but that has to be expected. It will be a very insignificant small digit.
So lets round the double after we took it from float into our desired precision.

Code:
void main()
{	
	double pip = 0.00001;
	float f1 = 0.0;
	float f2 = 0.0;
	double d1 = 0.0;
	double d2 = 0.0;
	int i;
	
	printf("nBusy...");
	
	for (i=0; i<0x7fffffff; ++i)
	{
		d1 += pip;
		f1 = d1;
		d2 = f1;
		if (round(d1,pip) != round(d2,pip))
		{
			printf("nMismatch %.5f vs %.5f", d1, d2);
			break;
		}
	}
	
	printf("nDone.");
}



Quote:
Busy...
Mismatch 128.00001 vs 128.00000
Done.


So the first mismatch with 0.00001 precision occurs at a relatively high value. Is that good enough? I think so yes.
Posted By: jcl

Re: TRADE struct encourages precision loss - 09/04/17 13:37

Floats are generally used for all structs that have a memory impact.
Posted By: pascalx

Re: TRADE struct encourages precision loss - 09/04/17 14:03

For above issue I use this workaround now. You can't use the parameters from enterLong/enterShort directly due the hidden conversion.

Code:
#define TMF_PTR_ARG 7

void* getTmfPointer(TRADE* pTrade)
{
	void* p = NULL;
	
	if (pTrade)
	{
		memcpy(&p, &pTrade->fArg[TMF_PTR_ARG], sizeof(float));
	}
	
	return p;
}

void setTmfPointer(TRADE* pTrade, void* p)
{
	if (pTrade)
	{
		memcpy(&pTrade->fArg[TMF_PTR_ARG], &p, sizeof(float));
	}
}


struct MyData
{
	int member1;
	int member2;
};

int tmf()
{
	struct MyData* pMyData = getTmfPointer(ThisTrade);
	return 0;
}

struct MyData g_myData;

void run()
{	
	if (Bar == StartBar)
	{
		TRADE* pTrade = enterLong(tmf);
		setTmfPointer(pTrade, &g_myData);
	}
}

© 2024 lite-C Forums