-
-
Notifications
You must be signed in to change notification settings - Fork 341
Open
Description
Description of Bug
Certain price values (such as 5.06) are not respected when creating a limit order
Code to Reproduce
from tda.orders.equities import equity_buy_limit
order = equity_buy_limit('AAPL', quantity=100, price=5.06)
print(order.build())
Expected Behavior
The resulting order should have a limit price of 5.06
Actual Behavior
Instead, the limit order has a price of 5.05
{'session': 'NORMAL', 'duration': 'DAY', 'orderType': 'LIMIT', 'price': '5.05', 'orderLegCollection': [{'instruction': 'BUY', 'instrument': {'assetType': 'EQUITY', 'symbol': 'AAPL'}, 'quantity': 100}], 'orderStrategyType': 'SINGLE'}
The error is in truncate_float
due to floating point rounding errors.
flt = 5.06
values = {
'flt': flt,
'flt * 100': flt * 100,
'int(flt * 100)': int(flt * 100),
'float(int(flt * 100))': float(int(flt * 100)),
'float(int(flt * 100)) / 100.0': float(int(flt * 100)) / 100.0,
"'{:.2f}'.format(float(int(flt * 100)) / 100.0)": '{:.2f}'.format(float(int(flt * 100)) / 100.0),
}
for key, value in values.items():
print(f'{key:<50}: {value}')
flt : 5.06
flt * 100 : 505.99999999999994
int(flt * 100) : 505
float(int(flt * 100)) : 505.0
float(int(flt * 100)) / 100.0 : 5.05
'{:.2f}'.format(float(int(flt * 100)) / 100.0) : 5.05
Notice how flt * 100
is 505.99999999999994
. A possible fix might be to add a small epsilon value (haven't tested negative values though):
def truncate_float_fixed(flt):
epsilon = 1e-7
if abs(flt) < 1 and flt != 0.0:
return '{:.4f}'.format(float(int((flt + epsilon) * 10000)) / 10000.0)
else:
return '{:.2f}'.format(float(int((flt + epsilon) * 100)) / 100.0)
print('BEFORE: ', truncate_float(5.06))
print('AFTER : ', truncate_float_fixed(5.06))
BEFORE: 5.05
AFTER : 5.06
Metadata
Metadata
Assignees
Labels
No labels