add
This commit is contained in:
297
ccxt/base/precise.py
Normal file
297
ccxt/base/precise.py
Normal file
@@ -0,0 +1,297 @@
|
||||
# Author: carlo.revelli@berkeley.edu
|
||||
#
|
||||
# Precise
|
||||
# Representation
|
||||
# Expanding
|
||||
# CCXT
|
||||
# Internal
|
||||
# Scientific
|
||||
# Exponents
|
||||
#
|
||||
# (╯°□°)╯︵ ┻━┻
|
||||
|
||||
|
||||
class Precise:
|
||||
def __init__(self, number, decimals=None):
|
||||
if decimals is None:
|
||||
modifier = 0
|
||||
number = number.lower()
|
||||
if 'e' in number:
|
||||
number, modifier = number.split('e')
|
||||
modifier = int(modifier)
|
||||
decimal_index = number.find('.')
|
||||
if decimal_index > -1:
|
||||
self.decimals = len(number) - decimal_index - 1
|
||||
self.integer = int(number.replace('.', ''))
|
||||
else:
|
||||
self.decimals = 0
|
||||
self.integer = int(number)
|
||||
self.decimals = self.decimals - modifier
|
||||
else:
|
||||
self.integer = number
|
||||
self.decimals = decimals
|
||||
self.base = 10
|
||||
|
||||
def __add__(self, other):
|
||||
return self.add(other)
|
||||
|
||||
def __sub__(self, other):
|
||||
return self.sub(other)
|
||||
|
||||
def __mul__(self, other):
|
||||
return self.mul(other)
|
||||
|
||||
def __truediv__(self, other):
|
||||
return self.div(other)
|
||||
|
||||
def __mod__(self, other):
|
||||
return self.mod(other)
|
||||
|
||||
def __neg__(self):
|
||||
return self.neg()
|
||||
|
||||
def __abs__(self):
|
||||
return self.abs()
|
||||
|
||||
def __min__(self, other):
|
||||
return self.min(other)
|
||||
|
||||
def __max__(self, other):
|
||||
return self.max(other)
|
||||
|
||||
def __lt__(self, other):
|
||||
return self.lt(other)
|
||||
|
||||
def __le__(self, other):
|
||||
return self.le(other)
|
||||
|
||||
def __gt__(self, other):
|
||||
return self.gt(other)
|
||||
|
||||
def __ge__(self, other):
|
||||
return self.ge(other)
|
||||
|
||||
def __eq__(self, other):
|
||||
if isinstance(other, str):
|
||||
# Allow comparisons with Precise("5") == "5"
|
||||
return str(self) == other
|
||||
return self.equals(other)
|
||||
|
||||
def mul(self, other):
|
||||
integer_result = self.integer * other.integer
|
||||
return Precise(integer_result, self.decimals + other.decimals)
|
||||
|
||||
def div(self, other, precision=18):
|
||||
distance = precision - self.decimals + other.decimals
|
||||
if distance == 0:
|
||||
numerator = self.integer
|
||||
elif distance < 0:
|
||||
exponent = self.base ** -distance
|
||||
numerator = self.integer // exponent
|
||||
else:
|
||||
exponent = self.base ** distance
|
||||
numerator = self.integer * exponent
|
||||
result, mod = divmod(numerator, other.integer)
|
||||
# python floors negative numbers down instead of truncating
|
||||
# if mod is zero it will be floored to itself so we do not add one
|
||||
result = result + 1 if result < 0 and mod else result
|
||||
return Precise(result, precision)
|
||||
|
||||
def add(self, other):
|
||||
if self.decimals == other.decimals:
|
||||
integer_result = self.integer + other.integer
|
||||
return Precise(integer_result, self.decimals)
|
||||
else:
|
||||
smaller, bigger = [other, self] if self.decimals > other.decimals else [self, other]
|
||||
exponent = bigger.decimals - smaller.decimals
|
||||
normalised = smaller.integer * (self.base ** exponent)
|
||||
result = normalised + bigger.integer
|
||||
return Precise(result, bigger.decimals)
|
||||
|
||||
def sub(self, other):
|
||||
negative = Precise(-other.integer, other.decimals)
|
||||
return self.add(negative)
|
||||
|
||||
def abs(self):
|
||||
return Precise(abs(self.integer), self.decimals)
|
||||
|
||||
def neg(self):
|
||||
return Precise(-self.integer, self.decimals)
|
||||
|
||||
def mod(self, other):
|
||||
rationizerNumberator = max(-self.decimals + other.decimals, 0)
|
||||
numerator = self.integer * (self.base ** rationizerNumberator)
|
||||
rationizerDenominator = max(-other.decimals + self.decimals, 0)
|
||||
denominator = other.integer * (self.base ** rationizerDenominator)
|
||||
result = numerator % denominator
|
||||
return Precise(result, rationizerDenominator + other.decimals)
|
||||
|
||||
def orn(self, other):
|
||||
integer_result = self.integer | other.integer
|
||||
return Precise(integer_result, self.decimals)
|
||||
|
||||
def min(self, other):
|
||||
return self if self.lt(other) else other
|
||||
|
||||
def max(self, other):
|
||||
return self if self.gt(other) else other
|
||||
|
||||
def gt(self, other):
|
||||
add = self.sub(other)
|
||||
return add.integer > 0
|
||||
|
||||
def ge(self, other):
|
||||
add = self.sub(other)
|
||||
return add.integer >= 0
|
||||
|
||||
def lt(self, other):
|
||||
return other.gt(self)
|
||||
|
||||
def le(self, other):
|
||||
return other.ge(self)
|
||||
|
||||
def reduce(self):
|
||||
string = str(self.integer)
|
||||
start = len(string) - 1
|
||||
if start == 0:
|
||||
if string == "0":
|
||||
self.decimals = 0
|
||||
return self
|
||||
for i in range(start, -1, -1):
|
||||
if string[i] != '0':
|
||||
break
|
||||
difference = start - i
|
||||
if difference == 0:
|
||||
return self
|
||||
self.decimals -= difference
|
||||
self.integer = int(string[:i + 1])
|
||||
|
||||
def equals(self, other):
|
||||
self.reduce()
|
||||
other.reduce()
|
||||
return self.decimals == other.decimals and self.integer == other.integer
|
||||
|
||||
def __str__(self):
|
||||
self.reduce()
|
||||
sign = '-' if self.integer < 0 else ''
|
||||
integer_array = list(str(abs(self.integer)).rjust(self.decimals, '0'))
|
||||
index = len(integer_array) - self.decimals
|
||||
if index == 0:
|
||||
item = '0.'
|
||||
elif self.decimals < 0:
|
||||
item = '0' * (-self.decimals)
|
||||
elif self.decimals == 0:
|
||||
item = ''
|
||||
else:
|
||||
item = '.'
|
||||
integer_array.insert(index, item)
|
||||
return sign + ''.join(integer_array)
|
||||
|
||||
def __repr__(self):
|
||||
return "Precise(" + str(self) + ")"
|
||||
|
||||
def __float__(self):
|
||||
return float(str(self))
|
||||
|
||||
@staticmethod
|
||||
def string_mul(string1, string2):
|
||||
if string1 is None or string2 is None:
|
||||
return None
|
||||
return str(Precise(string1).mul(Precise(string2)))
|
||||
|
||||
@staticmethod
|
||||
def string_div(string1, string2, precision=18):
|
||||
if string1 is None or string2 is None:
|
||||
return None
|
||||
string2_precise = Precise(string2)
|
||||
if string2_precise.integer == 0:
|
||||
return None
|
||||
return str(Precise(string1).div(string2_precise, precision))
|
||||
|
||||
@staticmethod
|
||||
def string_add(string1, string2):
|
||||
if string1 is None and string2 is None:
|
||||
return None
|
||||
if string1 is None:
|
||||
return string2
|
||||
elif string2 is None:
|
||||
return string1
|
||||
return str(Precise(string1).add(Precise(string2)))
|
||||
|
||||
@staticmethod
|
||||
def string_sub(string1, string2):
|
||||
if string1 is None or string2 is None:
|
||||
return None
|
||||
return str(Precise(string1).sub(Precise(string2)))
|
||||
|
||||
@staticmethod
|
||||
def string_abs(string):
|
||||
if string is None:
|
||||
return None
|
||||
return str(Precise(string).abs())
|
||||
|
||||
@staticmethod
|
||||
def string_neg(string):
|
||||
if string is None:
|
||||
return None
|
||||
return str(Precise(string).neg())
|
||||
|
||||
@staticmethod
|
||||
def string_mod(string1, string2):
|
||||
if string1 is None or string2 is None:
|
||||
return None
|
||||
return str(Precise(string1).mod(Precise(string2)))
|
||||
|
||||
@staticmethod
|
||||
def string_or(string1, string2):
|
||||
if string1 is None or string2 is None:
|
||||
return None
|
||||
return str(Precise(string1).orn(Precise(string2)))
|
||||
|
||||
@staticmethod
|
||||
def string_equals(string1, string2):
|
||||
if string1 is None or string2 is None:
|
||||
return None
|
||||
return Precise(string1).equals(Precise(string2))
|
||||
|
||||
@staticmethod
|
||||
def string_eq(string1, string2):
|
||||
if string1 is None or string2 is None:
|
||||
return None
|
||||
return Precise(string1).equals(Precise(string2))
|
||||
|
||||
@staticmethod
|
||||
def string_min(string1, string2):
|
||||
if string1 is None or string2 is None:
|
||||
return None
|
||||
return str(Precise(string1).min(Precise(string2)))
|
||||
|
||||
@staticmethod
|
||||
def string_max(string1, string2):
|
||||
if string1 is None or string2 is None:
|
||||
return None
|
||||
return str(Precise(string1).max(Precise(string2)))
|
||||
|
||||
@staticmethod
|
||||
def string_gt(string1, string2):
|
||||
if string1 is None or string2 is None:
|
||||
return None
|
||||
return Precise(string1).gt(Precise(string2))
|
||||
|
||||
@staticmethod
|
||||
def string_ge(string1, string2):
|
||||
if string1 is None or string2 is None:
|
||||
return None
|
||||
return Precise(string1).ge(Precise(string2))
|
||||
|
||||
@staticmethod
|
||||
def string_lt(string1, string2):
|
||||
if string1 is None or string2 is None:
|
||||
return None
|
||||
return Precise(string1).lt(Precise(string2))
|
||||
|
||||
@staticmethod
|
||||
def string_le(string1, string2):
|
||||
if string1 is None or string2 is None:
|
||||
return None
|
||||
return Precise(string1).le(Precise(string2))
|
||||
Reference in New Issue
Block a user