Carl - 1 year ago 35

Python Question

I have a nested loop structure to generate a large number of backtests by varying the value of 4 variables, oq, aq, lev, and val. The idea is to execute every combination of the variables below within the ranges provided.

Without a constraint, this loop would therefore execute a total of 5 * 6 * 5 * 5 = 750 times which at ~5-10 seconds each would take several hours. However, there is a constraint, which is that all the weights must sum to exactly 1 (tot_wgt). By adding an if statement, I hoped to simply discard such cases.

`if (tot_wgt != 1):`

continue

Unfortunately, the code still seems to execute sometimes when tot_wgt does not have a value of 1. This seems to happen every time the val loop has completed a cycle (and presumably also happens when each of the other 3 loops have completed a cycle).

Problem solved: I had an indentation error: my needed to be at the level of the if statement. But see the excellent answer on recognition of floating point numbers.

`mom = 0`

for oq in [0.3, 0.4, 0.5, 0.6, 0.7]:

for aq in [0.05, 0.1, 0.15, 0.2, 0.25, 0.3]:

for lev in [0.0, 0.05, 0.1, 0.15, 0.2]:

for val in [0.0, 0.05, 0.1, 0.15, 0.2]:

tot_wgt = oq + aq + lev + val + mom

if (tot_wgt != 1): #we only want to backtest where the weights add up to 1. If <1 or >1, simply skip

continue

<MAIN BACKTEST CODE HERE>

Answer

This is caused by the limitations of representing floating-point numbers in computer hardware as base 2 (binary) fractions. Refer to Floating Point Arithmetic: Issues and Limitations for the detailed description.

For instance, in your case,

```
>>> 0.7 + 0.2 + 0.0 + 0.1 + 0
0.9999999999999999
# more specific
>>> from decimal import Decimal
>>> Decimal(0.7 + 0.2 + 0.0 + 0.1 + 0)
Decimal('0.99999999999999988897769753748434595763683319091796875')
```

As you can see, this is not equvelent to `1`

. One simple way to resolve it is just to replace the line `if (tot_wgt != 1):`

with,

```
if abs(tot_wgt - 1) < 0.0001 :
```

Python 3.5 adds the `math.isclose`

for testing approximate equality. For an earlier version, the equivalent function is as follows.

```
def isclose(a, b, rel_tol=1e-09, abs_tol=0.0):
return abs(a-b) <= max(rel_tol * max(abs(a), abs(b)), abs_tol)
```

Use `numpy.isclose`

to test if two arrays are element-wise equal within a tolerance.

```
# Usage
numpy.isclose(a, b, rtol=1e-05, atol=1e-08, equal_nan=False)
# An example
>>> import numpy as np
>>> np.isclose([1e10,1e-7], [1.00001e10,1e-8])
array([True, False])
```