python-bittrex
python-bittrex copied to clipboard
BUG FIX: decimal vs float. And timestamp issue!
HELLO, I am writing to share a bug and it's fix i found in the program. Issue is that '.json' converts string numbers to floats. Float's should NOT be used within financial applications! IEEE 754 is not for exact numerical representation but for approximate representation by representation numbers on a fractional base 2. Decimal should be used when exact representation is necessary. https://docs.python.org/2/library/decimal.html
Not using decimal over float can cause a situation when your balances or market value come back incorrect causing a failed trade. Note: decimals cannot be constructed correctly using .from_float method. float vs decimal...
floats:
0.1*3
answer: 0.30000000000000004 # incorrect
decimal:
Decimal("0.1") * Decimal("3")
answer: Decimal('0.3') # correct
BUG FIX:
from decimal import Decimal
...
def using_requests(request_url, apisign):
def dec(s): return Decimal(str(s)) # BUG FIX
response = requests.get(
request_url,
headers={"apisign": apisign}
).json(parse_float=dec) # BUG FIX
return response
thanks for pointing this out. This seems like a good candidate for a pull request
I have found another issue that I feel belongs in this library. two issues: (1) the library should convert timestamps -> datetime's. (2) bittrex returns an incorrect timestamp when milliseconds are all zero's. I am doing a sloppy recursive search for key names because bittrex documents are horrible and i don't know all the places across methods this occurs on. Attached is the code I am using to fix these issues...
# write own method to use against other datasources
def using_requests(request_url, apisign):
def dec(s): return Decimal(str(s))
response = requests.get( #timeout issue?
request_url,
headers={"apisign": apisign}
).json(parse_float=dec)
# region fix and cast datetime fields
# recursively search for specific keys to fix
def fix_datetime(s):
if s.find('.') == -1:
s = s + ".000" # BITTREX BUG FIX: they will strip out .000, add it back so we can process and keep consistent
s = datetime.datetime.strptime(s, '%Y-%m-%dT%H:%M:%S.%f')
return s
def datetime_fix_fx(node):
datetime_fields = ['Created', 'TimeStamp'] # might be more?
if isinstance(node, dict):
for k,v in node.items():
if isinstance(v, list):
for _ in v:
datetime_fix_fx(_)
if isinstance(v, dict):
datetime_fix_fx(v) # call recursively
elif isinstance(v, str) and k in datetime_fields:
node[k] = fix_datetime(v)
datetime_fix_fx(response)
# endregion
return response