Files
ccxt_with_mt5/ccxt/base/precise.py
lz_db 0fab423a18 add
2025-11-16 12:31:03 +08:00

298 lines
8.7 KiB
Python

# 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))