def auto_scaler(ind_var, ticks): ''''this fucntion automatically creates scale and tick distance''' value_range = (max(ind_var) - min(ind_var)) dist_per_tick = Decimal(value_range / ticks) exponent = dist_per_tick.adjusted() g = ((dist_per_tick * 2).quantize( Decimal(str(10**(dist_per_tick.adjusted()))), rounding=ROUND_UP)) / 2 if round((g / Decimal(10**exponent)), 1) == 2.5 or round( (g / Decimal(10**exponent)), 1) == 7.5: b = g else: b = dist_per_tick.quantize(Decimal(str( 10**(dist_per_tick.adjusted()))), rounding=ROUND_UP) lower_bound = b * (Decimal(min(ind_var)) // b) if Decimal(max(ind_var)) % b == 0: upper_bound = max(ind_var) else: upper_bound = b * (1 + Decimal(max(ind_var)) // b) print(lower_bound) print(upper_bound) print(b)
def nthroot(A, n:int,*, precision:int=None,decimales:int=None) -> Decimal: """Calcula la raiz n-esima de A""" #https://en.wikipedia.org/wiki/Nth_root#Logarithmic_computation if n>1: if A>0: DA = Decimal(A) #N = Decimal(n) if not precision: dec = 21 + (decimales if decimales else 0) precision = max( 42+dec, ((abs(DA.adjusted())+1)//n ) + dec ) #21 y 42 números arbitrarios para minimizar #errores de redondeo y entregar un numero #con precicion más que suficiente para lo #que se necesite. Se eligio 42 ya que es la #respuesta al universo, y 21 por se la mitad #de la respuesta with localcontext() as ctx: ctx.prec = precision resul = Decimal( DA.ln() / n ).exp() return resul if decimales is None else round(resul,decimales) elif A==0: return Decimal(0) else: if n%2==0: raise ValueError("Raiz par de un número negativo") return - nthroot(-A, n, precision=precision, decimales=decimales) else: raise ValueError("El indice de la raiz debe ser mayor que 1")
def parse_market(self, market): # { # symbol: "BTC", # contract_code: "BTC190906", # contract_type: "this_week", # contract_size: 100, # price_tick: 0.01, # delivery_date: "20190906", # create_date: "20190823", # contract_status: 1 # } defaultType = self.safe_string_2(self.options, 'fetchMarkets', 'defaultType', 'futures') base = baseId = market['symbol'] if 'contract_type' in market: quote = quoteId = 'USD' market_type = 'futures' expiration = self.expirations[market['contract_type']] symbol = f'{baseId}_{expiration}' else: quote = quoteId = market['contract_code'].split('-')[1] market_type = defaultType symbol = f'{base}-{quote}' active = (self.safe_integer(market, 'contract_status') == 1) price_tick = Decimal(market['price_tick']) exp = price_tick.adjusted() mantissa = price_tick.scaleb(-exp) if round(mantissa) == 10: price_precision = -exp - 1 else: price_precision = -exp return { 'id': symbol, 'symbol': symbol, 'base': base, 'quote': quote, 'baseId': baseId, 'quoteId': quoteId, 'type': market_type, 'active': active, 'precision': { 'amount': 0, 'price': price_precision, }, 'limits': { 'amount': { 'min': 1, 'max': None, }, 'price': { 'min': None, 'max': None }, 'cost': { 'min': None, 'max': None } }, 'info': market, }
def calc_price_step_min(auction): price_step_min = current_app.config["YAMI_PRICE_STEP_MIN"] if auction["price_step_min"] > price_step_min: price_step_min = auction["price_step_min"] price_reference = auction["price_current_low"] if current_app.config[ "YAMI_PRICE_STEP_FROM_CURRENT_PRICE"] else auction["price_start"] if price_reference == 0: return price_step_min price_reference = Decimal(price_reference) exponent = price_reference.adjusted() exp10 = Decimal(1).scaleb(exponent) mantissa = price_reference / exp10 rule = current_app.config["YAMI_PRICE_STEP_RULE"] rkeys = sorted(rule.keys()) for i in range(len(rule) - 1): if mantissa >= rkeys[i] and mantissa < rkeys[i + 1]: step_from_rule = exp10 * rule[rkeys[i]] break else: step_from_rule = exp10 * rule[rkeys[-1]] step_from_rule = int(step_from_rule) if step_from_rule > price_step_min: price_step_min = step_from_rule return price_step_min
def scientificformat(text): """ Displays a float in scientific notation. If the input float is infinity or NaN, the (platform-dependent) string representation of that value will be displayed. This is based on the floatformat function in django/template/defaultfilters.py """ try: input_val = force_unicode(text) d = Decimal(input_val) except UnicodeEncodeError: return u'' except InvalidOperation: if input_val in special_floats: return input_val try: d = Decimal(force_unicode(float(text))) except (ValueError, InvalidOperation, TypeError, UnicodeEncodeError): return u'' try: m = int(d) - d except (ValueError, OverflowError, InvalidOperation): return input_val try: # for 'normal' sized numbers if d.is_zero(): number = u'0' elif ( (d > Decimal('-100') and d < Decimal('-0.1')) or ( d > Decimal('0.1') and d < Decimal('100')) ) : # this is what the original floatformat() function does sign, digits, exponent = d.quantize(Decimal('.01'), ROUND_HALF_UP).as_tuple() digits = [unicode(digit) for digit in reversed(digits)] while len(digits) <= abs(exponent): digits.append(u'0') digits.insert(-exponent, u'.') if sign: digits.append(u'-') number = u''.join(reversed(digits)) else: # for very small and very large numbers sign, digits, exponent = d.as_tuple() exponent = d.adjusted() digits = [unicode(digit) for digit in digits][:3] # limit to 2 decimal places while len(digits) < 3: digits.append(u'0') digits.insert(1, u'.') if sign: digits.insert(0, u'-') number = u''.join(digits) number += u'e' + u'%i' % exponent return mark_safe(formats.number_format(number)) except InvalidOperation: return input_val
def get_round_price(price: Decimal) -> Decimal: one_dollar = Decimal('1.00') if price > one_dollar: return price.quantize(Decimal('0.01')) exponent = price.adjusted() shifted = price.shift(abs(exponent)) rounded = shifted.quantize(Decimal('0.01')) return rounded.scaleb(exponent)
def round_to_uncertainty(value, uncertainty): """Helper function for round_result.""" # round the uncertainty to 1-2 significant digits u = Decimal(uncertainty).normalize() exponent = u.adjusted() # find position of the most significant digit precision = (u.as_tuple().digits[0] == 1) # is the first digit 1? u = u.scaleb(-exponent).quantize(Decimal(10)**-precision) # round the value to remove excess digits return round(Decimal(value).scaleb(-exponent).quantize(u)), u, exponent
def resolve_entry_price(self, info, **kwargs): price = self.get("price") if price is None: raise ValueError( f'Expecting a value for entry_price. Got: "{price}"') value = Decimal(str(price)) if value.adjusted() >= 0: return value.quantize(Decimal('0.01')) return value
def resolve_price_paid(self, info, **kwargs): price_paid = self.get("pricePaid") if price_paid is None: raise ValueError( f'Expecting a value for price_paid. Got: "{price_paid}"') value = Decimal(str(price_paid)) if value.adjusted() >= 0: return value.quantize(Decimal('0.01')) return value
def resolve_stop_limit_price(self, info, **kwargs): details = self.get("OrderDetail")[0] stop_limit_price = details.get("stopLimitPrice") if not stop_limit_price and stop_limit_price != 0: return None value = Decimal(str(stop_limit_price)) if value.adjusted() > 0: return value.quantize(Decimal('0.01')) return value
def pow(a, n): r = Decimal(1) while n: if n & 1: r *= a n >>= 1 a *= a a /= Decimal(10**a.adjusted()) r /= Decimal(10**r.adjusted()) return r
def fmt_prob(prob, prec=4): """ Format a float as a string in a style suitable for displaying probabilities. This is not a particularly quick procedure. If you need to format lots of probabilities, it's probably best to do something cruder. """ from decimal import Decimal # Quantize the value to the correct precision prob = Decimal(str(prob)) #.as_tuple() quant = Decimal((0, [ 1, ], prob.adjusted() - prec + 1)) prob = prob.quantize(quant) # Format it yourself, because Decimal's to_sci_string is crap tup = prob.as_tuple() sci_str = "%s%d.%se%d" % ("-" if prob.is_signed() else "", tup.digits[0], "".join(["%d" % dig for dig in tup.digits[1:] ]), prob.adjusted()) # Add more spacing for higher precisions #fmt_str = " >%ds" % (prec+3) return sci_str #format(sci_str, fmt_str)
def get_limit_price(action: OrderAction, price: Decimal, margin: Decimal) -> Decimal: one_dollar = Decimal('1.00') if price < one_dollar: exponent = price.adjusted() quantum = Decimal(str(1 / (10**(abs(exponent) + 2)))) shifted = price.shift(abs(exponent)) shifted = shifted + margin if action.buying() else shifted - margin limit_price = shifted.scaleb(exponent) limit_price = limit_price.quantize(quantum) else: limit_price = price + margin if action.buying() else price - margin limit_price = limit_price.quantize(Decimal('0.01')) return limit_price
def __round__(self, p: int = 0) -> labfloat: """Round labfloat's mean and uncertainty at p decimal places. When no arguments are passed or p=0, the mean and uncertainty will round at the uncertainty most significant figure to nearest with ties going away from zero (Round half away from zero) using Python's ROUND_HALF_UP. If a value is passe to p it will round at p decimal places, and if p is greater than the error's most significant figure decimal place, the error will be one at the mean's least significant figure decimal place. Args: p (int, optional): The number of decimals to use when rounding. Defaults to 0. Returns: labfloat: New labfloat with the rounded mean and error. """ current_contex = getcontext() setcontext(self.context) u = Decimal(str(self._uncertainty)) m = Decimal(str(self._mean)) r = p - u.adjusted() * (not p) u = round(u, r) r = p - u.adjusted() * (not p) u += Decimal("1e{}".format(-r)) * (not u) m = round(m, r) setcontext(current_contex) return labfloat(type(self._mean)(m), type(self._uncertainty)(u))
def fmt_prob(prob, prec=4): """ Format a float as a string in a style suitable for displaying probabilities. This is not a particularly quick procedure. If you need to format lots of probabilities, it's probably best to do something cruder. """ from decimal import Decimal # Quantize the value to the correct precision prob = Decimal(str(prob))#.as_tuple() quant = Decimal((0, [1,], prob.adjusted()-prec+1)) prob = prob.quantize(quant) # Format it yourself, because Decimal's to_sci_string is crap tup = prob.as_tuple() sci_str = "%s%d.%se%d" % ("-" if prob.is_signed() else "", tup.digits[0], "".join(["%d" % dig for dig in tup.digits[1:]]), prob.adjusted()) # Add more spacing for higher precisions #fmt_str = " >%ds" % (prec+3) return sci_str #format(sci_str, fmt_str)
def general_format(x, precision: int = 2, pad: int = 10, left: bool = False, fmt: str = 'D') -> str: """General formatter. Parameters ---------- x: str The number (string castable) to be formatted precision: int The precision of the formatter. In sig figs pad: int The amount to pad the string to left_pad: bool If False will right pad the string, fmt: str The delimiting string between the # and the exp Returns ------- str The formatted number as a string """ x = Decimal(str(x)) tup = x.as_tuple() digits = list(tup.digits[:precision + 1]) sign = '-' if tup.sign else '+' dec = ''.join(map(str, digits[1:])) exp = x.adjusted() ret = f'{sign}{digits[0]}.{dec}{fmt}{exp}' if not pad: return ret if not left: return ret.rjust(pad) return ret.ljust(pad)
class SigFig: """ Follows the rules of significant figures 1. All non zero numbers are significant 2. Zeros located between non-zero digits are significant 3. Trailing zeros are significant only if the number contains a decimal 4. Zeros to left of the first nonzero digit are insignificant Exact Numbers: exact counts don't affect sigfigs in calculations and are said to have an infinite number of significant figures """ _Inf = float("inf") def __new__(cls, value: Union[str, int, 'SigFig', Decimal], exact=False, precision=None, decimalplaces=None): self = object.__new__(cls) try: self.value = Decimal(value) except TypeError as e: if hasattr(value, "value"): self.value = Decimal(value.value) else: raise TypeError(f"cant convert from {value!r} to SigFig") from e if decimalplaces is None and precision is None: if '.' not in str(value): # no decimal . remove trailing zeroes self.value = self.value.normalize() else: if precision is not None: # if u are given a precision compute the best one given precision dp = precision - self.value.adjusted() - 1 decimalplaces = dp if decimalplaces is None else min(dp, decimalplaces) self.value = self.value.__round__(decimalplaces) if exact: self.precision = SigFig._Inf self.decimal_places = SigFig._Inf else: self.precision = len(self.value.as_tuple().digits) self.decimal_places = self.precision - self.value.adjusted() - 1 return self def __str__(self): if self.decimal_places == SigFig._Inf: return f"{self.value}" try: return f"{round(self.value, self.decimal_places)}" except decimal.InvalidOperation: return f"{self.value}" def __repr__(self): if self.precision == SigFig._Inf: return f"SigFig({str(self)!r},exact=True)" else: return f"SigFig({str(self)!r})" def __add__(self, other): """addition keeps the number of least precise decimal""" if not isinstance(other, self.__class__): other = self.__class__(other) return SigFig(self.value + other.value, decimalplaces=min(self.decimal_places, other.decimal_places)) __radd__ = __add__ def __sub__(self, other): """subtraction keeps the number of least precise decimal""" if not isinstance(other, self.__class__): other = self.__class__(other) return SigFig(self.value - other.value, decimalplaces=min(self.decimal_places, other.decimal_places)) def __rsub__(self, other): if not isinstance(other, self.__class__): other = self.__class__(other) return other - self def __mul__(self, other): """multiplication keeps the precision of number with the least amount of sigfigs""" if not isinstance(other, self.__class__): other = self.__class__(other) return SigFig(self.value * other.value, precision=min(self.precision, other.precision)) __rmul__ = __mul__ def __truediv__(self, other): """division keeps the precision of number with the least amount of sigfigs""" if not isinstance(other, self.__class__): other = self.__class__(other) return SigFig(self.value / other.value, precision=min(self.precision, other.precision)) def __rtruediv__(self, other): if not isinstance(other, self.__class__): other = self.__class__(other) return other / self def __neg__(self): return SigFig(-self.value, decimalplaces=self.decimalplaces, precision=self.precision) def __eq__(self, other): if hasattr(other, "value"): return self.value == other.value return self.value == Decimal(other) def __lt__(self, other): if hasattr(other, "value"): return self.value < other.value return self.value < Decimal(other) def __le__(self, other): if hasattr(other, "value"): return self.value <= other.value return self.value <= Decimal(other)
def calc_spc(Val, Series): # INPUT VALUES # replace with user input routine!!! targValue = Decimal('{}'.format(Val)) targSer = '{}'.format(Series) print('Target Value: {} \nTarget Series: {}\n'.format(targValue, targSer)) # # Set e-Values List from 1 decades below to 1 decades above target value valuesMat = valMat(targSer, targValue.adjusted() - 1, targValue.adjusted() + 1) # # Closest Value closestVal = Decimal('inf') for x in range(len(valuesMat)): if abs( min(valuesMat[x], key=lambda x: abs(x - targValue)) - targValue) < abs(closestVal - targValue): closestVal = min(valuesMat[x], key=lambda x: abs(x - targValue)) print("Closest single value: {}\n".format(closestVal)) # # Closest combinations # NOTE: only finds the first of equally close pairs! tmpSerDev = Decimal('inf') tmpParDev = Decimal('inf') for m in range(len(valuesMat)): for n in range(len(valuesMat[0])): for i in range( len(valuesMat) ): # TRY TO CHANGE INNER ROUTINE TO lambda AND COMPARE SPEEDS! for j in range(len(valuesMat[0])): series = valuesMat[i][j] + valuesMat[m][n] parallel = (valuesMat[i][j] * valuesMat[m][n]) / ( valuesMat[i][j] + valuesMat[m][n]) if abs(series - targValue) < tmpSerDev: tmpSerDev = abs(series - targValue) serVal1 = valuesMat[i][j] serVal2 = valuesMat[m][n] if abs(parallel - targValue) < tmpParDev: tmpParDev = abs(parallel - targValue) parVal1 = valuesMat[i][j] parVal2 = valuesMat[m][n] closestDev = ((closestVal / targValue - 1) * 100).quantize(Decimal('1.00')) serComb = serVal1 + serVal2 serDevPerc = ((serComb / targValue - 1) * 100).quantize(Decimal('1.00')) parComb = ((parVal1 * parVal2) / (parVal1 + parVal2)).quantize( Decimal('1.00')) parDevPerc = ((parComb / targValue - 1) * 100).quantize(Decimal('1.00')) # print("Closest series combination: {} + {} = {}".format( str(serVal1), str(serVal2), str(serComb))) print("Deviation from Target Value: {}%\n".format(str(serDevPerc))) # print("Closest parallel combination: {} + {} = {}".format( str(parVal1), str(parVal2), str(parComb))) print("Deviation from Target Value: {}%\n".format(str(parDevPerc))) vals_and_dev = { "cVal": closestVal, "cDev": closestDev, "sVal1": serVal1, "sVal2": serVal2, "sComb": serComb, "sDev": serDevPerc, "pVal1": parVal1, "pVal2": parVal2, "pComb": parComb, "pDev": parDevPerc } return vals_and_dev
def parse_market(self, market): # { # symbol: "BTC", # contract_code: "BTC190906", # contract_type: "this_week", # contract_size: 100, # price_tick: 0.01, # delivery_date: "20190906", # create_date: "20190823", # contract_status: 1 # } if 'delivery_date' in market: market_type = 'futures' base = baseId = market['symbol'] quote = quoteId = 'USD' expiration = self.expirations[market['contract_type']] symbol = f'{base}_{expiration}' else: symbol = market['contract_code'] base, quote = symbol.split('-') if quote == 'USDT': market_type = 'swap.usdt' base, quote = quote, base else: market_type = 'swap' baseId = base quoteId = quote active = (self.safe_integer(market, 'contract_status') == 1) price_tick = Decimal(market['price_tick']) exp = price_tick.adjusted() mantissa = price_tick.scaleb(-exp) if round(mantissa) == 10: price_precision = -exp - 1 else: price_precision = -exp return { 'id': symbol, 'symbol': symbol, 'base': base, 'quote': quote, 'baseId': baseId, 'quoteId': quoteId, 'type': market_type, 'active': active, 'precision': { 'amount': 0, 'price': price_precision, }, 'limits': { 'amount': { 'min': 1, 'max': None, }, 'price': { 'min': None, 'max': None }, 'cost': { 'min': None, 'max': None } }, 'info': market, }
adjusted() return the adjusted exponent as_integer_ratio() return a pair (n, d) of integers that represent the given Decimal instance as a fraction as_tuple() return a named tuple DecimalTuple(sign, digits, exponent) copy_abs() return the absolute value of the argument copy_sign(other) return a copy of the first operand with the sign set to be the same as other exp() return the value of the (natural) exponential function e**x at the given number quantize(exp, rounding=None) round a number to a fixed exponent Rounding modes decimal.ROUND_CEILING round towards Infinity decimal.ROUND_FLOOR round towards -Infinity decimal.ROUND_UP round away from zero decimal.ROUND_DOWN round towards zero decimal.ROUND_HALF_UP round to nearest with ties going away from zero. decimal.ROUND_HALF_DOWN round to nearest with ties going towards zero decimal.ROUND_HALF_EVEN round to nearest with ties going to nearest even integer """ import decimal from decimal import Decimal a = Decimal(-139) + Decimal('-2e-5') + Decimal('1.53') print(a) print(a.adjusted()) # the position of the most significant digit with respect to the decimal point print(a.as_integer_ratio()) print(a.as_tuple()) # sign 0 for positive or 1 for negative print(a.copy_abs(), a.quantize(Decimal('1.000'), rounding=decimal.ROUND_UP)) b = Decimal(15) print(a, b, a + b, a - b, a * b, a / b)