This PR is to address issues #376 #416 and #368 where the use of non-integer positions and floating point errors result in the np.isclose condition of allocate in SecurityBase to fail to be met, resulting in the "Potentially infinite loop detected..." error being thrown.
def allocate(self, amount, update=True):
...
if not q == -self._position:
full_outlay, _, _, _ = self.outlay(q)
...
while not np.isclose(full_outlay, amount, rtol=TOL) and q != 0:
dq_wout_considering_tx_costs = (full_outlay - amount) / (self._price * self.multiplier)
q = q - dq_wout_considering_tx_costs
...
i = i + 1
if i > 1e4:
raise Exception(
"Potentially infinite loop detected. This occurred "
"while trying to reduce the amount of shares purchased"
" to respect the outlay <= amount rule. This is most "
"likely due to a commission function that outputs a "
"commission that is greater than the amount of cash "
"a short sale can raise."
)
As described in #368 and #416, setting rtol to a non-zero, minuscule value like rtol=1e-14 addresses this issue, though in my experience with this error, it sometimes needs to be relaxed up to rtol=1e12.
I think setting rtol=TOL where TOL=1e-16 as per its use in is_zero is a good first step towards resolving this issue.
def is_zero(x):
"""
Test for zero that is robust against floating point precision errors
"""
return abs(x) < TOL
The global value for TOL = 1e-16 is never used anywhere else and is perhaps best also applied here since they are both floating point issues.
This PR is to address issues #376 #416 and #368 where the use of non-integer positions and floating point errors result in the
np.isclose
condition ofallocate
inSecurityBase
to fail to be met, resulting in the "Potentially infinite loop detected..." error being thrown.As described in #368 and #416, setting
rtol
to a non-zero, minuscule value likertol=1e-14
addresses this issue, though in my experience with this error, it sometimes needs to be relaxed up tortol=1e12
.I think setting
rtol=TOL
whereTOL=1e-16
as per its use inis_zero
is a good first step towards resolving this issue.The global value for
TOL = 1e-16
is never used anywhere else and is perhaps best also applied here since they are both floating point issues.