Skip to content

Commit

Permalink
Merge branch 'frosty00-transpileTests'
Browse files Browse the repository at this point in the history
  • Loading branch information
kroitor committed May 31, 2018
2 parents 4c961be + f3e1a71 commit 5ae6e9c
Show file tree
Hide file tree
Showing 9 changed files with 1,066 additions and 709 deletions.
2 changes: 1 addition & 1 deletion ccxt.php
Expand Up @@ -37,4 +37,4 @@
$file = PATH_TO_CCXT . $class_name . '.php';
if (file_exists ($file))
require_once ($file);
} );
});
4 changes: 2 additions & 2 deletions js/base/functions/throttle.js
Expand Up @@ -8,7 +8,7 @@ const { sleep
/* ------------------------------------------------------------------------ */

module.exports = {

throttle: function throttle (cfg) {

let lastTimestamp = now ()
Expand All @@ -18,7 +18,7 @@ module.exports = {

const queue = []

return Object.assign (cost => {
return Object.assign ((cost) => {

if (queue.length > cfg.maxCapacity)
throw new Error ('Backlog is over max capacity of ' + cfg.maxCapacity)
Expand Down
220 changes: 103 additions & 117 deletions js/test/base/functions/test.number.js

Large diffs are not rendered by default.

7 changes: 5 additions & 2 deletions package.json
Expand Up @@ -16,17 +16,20 @@
"build": "npm run export-exchanges && npm run vss && npm run pandoc-python-readme && npm run pandoc-doc-readme && npm run pandoc-doc-faq && npm run pandoc-doc-manual && npm run pandoc-doc-install && npm run pandoc-doc-exchanges && npm run pandoc-doc-exchanges-by-country && npm run check-js-syntax && npm run transpile && npm run qa && npm run update-badges && npm run browserify",
"test": "npm run build && node run-tests",
"fast-test": "node run-tests --js",
"test-base": "mocha --reporter spec js/test/base/test.base.js --reporter ololog/reporter",
"test-base": "npm run test-js-base && npm run test-python-base && npm run test-php-base",
"test-js-base": "mocha --reporter spec js/test/base/test.base.js --reporter ololog/reporter",
"test-python-base": "python python/test/test_decimal_to_precision.py",
"test-php-base": "php -f php/test/decimal_to_precision.php",
"export-exchanges": "node export-exchanges",
"update-badges": "node update-badges",
"convert-md-2-rst": "bash ./convert-md-2-rst",
"transpile": "node transpile",
"vss": "node vss",
"qa": "cp package.json LICENSE.txt keys.json python && npm run check-python-syntax && npm run check-php-syntax",
"lint": "eslint",
"check-js-syntax": "eslint 'js/*.js'",
"check-python-syntax": "cd python && tox -e qa && cd ..",
"check-php-syntax": "php -f php/test/syntax.php",
"check-js-syntax": "eslint 'js/*.js'",
"browserify": "browserify --debug ./ccxt.browser.js > ./build/ccxt.browser.js",
"pandoc-python-readme": "pandoc --wrap=preserve --columns=10000 --from=markdown --to=rst --output=python/README.rst README.md",
"pandoc-doc-readme": "pandoc --wrap=preserve --columns=10000 --from=markdown --to=rst --output=doc/README.rst README.md",
Expand Down
3 changes: 3 additions & 0 deletions php/Exchange.php
Expand Up @@ -1806,6 +1806,7 @@ public static function decimalToPrecision ($x, $roundingMode = ROUND, $numPrecis
}

public static function decimal_to_precision ($x, $roundingMode = ROUND, $numPrecisionDigits = null, $countingMode = DECIMAL_PLACES, $paddingMode = NO_PADDING) {

if ($numPrecisionDigits < 0) {
throw new BaseError ('Negative precision is not yet supported');
}
Expand All @@ -1818,6 +1819,8 @@ public static function decimal_to_precision ($x, $roundingMode = ROUND, $numPrec
throw new BaseError ('Invalid number');
}

assert ($roundingMode === ROUND || $roundingMode === TRUNCATE);

$result = '';
if ($roundingMode === ROUND) {
if ($countingMode === DECIMAL_PLACES) {
Expand Down
164 changes: 164 additions & 0 deletions php/test/decimal_to_precision.php
@@ -0,0 +1,164 @@
<?php

namespace ccxt;

include_once ('./php/Exchange.php');

// ----------------------------------------------------------------------------
// testDecimalToPrecisionErrorHandling
//
// $this->expectException ('ccxt\\BaseError');
// $this->expectExceptionMessageRegExp ('/Negative precision is not yet supported/');
// Exchange::decimalToPrecision ('123456.789', TRUNCATE, -2, DECIMAL_PLACES);
//
// $this->expectException ('ccxt\\BaseError');
// $this->expectExceptionMessageRegExp ('/Invalid number/');
// Exchange::decimalToPrecision ('foo');

// ----------------------------------------------------------------------------

// PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
// https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code

// ----------------------------------------------------------------------------

function decimal_to_precision ($x, $roundingMode = ROUND, $numPrecisionDigits = null, $countingMode = DECIMAL_PLACES, $paddingMode = NO_PADDING) {
return Exchange::decimal_to_precision ($x, $roundingMode, $numPrecisionDigits, $countingMode, $paddingMode);
}

// ----------------------------------------------------------------------------
// number_to_string works, not supported in Python and PHP yet

// assert (number_to_string (-7.9e-7) === '-0.0000007899999999999999');
// assert (number_to_string ( 7.9e-7) === '0.0000007899999999999999');

// assert (number_to_string (-12.345) === '-12.345');
// assert (number_to_string ( 12.345) === '12.345');

// assert (number_to_string (0) === '0');

// ----------------------------------------------------------------------------
// testDecimalToPrecisionTruncationToNDigitsAfterDot

assert (decimal_to_precision ('12.3456000', TRUNCATE, 100, DECIMAL_PLACES) === '12.3456');
assert (decimal_to_precision ('12.3456', TRUNCATE, 100, DECIMAL_PLACES) === '12.3456');
assert (decimal_to_precision ('12.3456', TRUNCATE, 4, DECIMAL_PLACES) === '12.3456');
assert (decimal_to_precision ('12.3456', TRUNCATE, 3, DECIMAL_PLACES) === '12.345');
assert (decimal_to_precision ('12.3456', TRUNCATE, 2, DECIMAL_PLACES) === '12.34');
assert (decimal_to_precision ('12.3456', TRUNCATE, 1, DECIMAL_PLACES) === '12.3');
assert (decimal_to_precision ('12.3456', TRUNCATE, 0, DECIMAL_PLACES) === '12');

// assert (decimal_to_precision ('12.3456', TRUNCATE, -1, DECIMAL_PLACES) === '10'); // not yet supported
// assert (decimal_to_precision ('123.456', TRUNCATE, -2, DECIMAL_PLACES) === '120'); // not yet supported
// assert (decimal_to_precision ('123.456', TRUNCATE, -3, DECIMAL_PLACES) === '100'); // not yet supported

assert (decimal_to_precision ('0', TRUNCATE, 0, DECIMAL_PLACES) === '0');

// ----------------------------------------------------------------------------
// testDecimalToPrecisionTruncationToNSignificantDigits

assert (decimal_to_precision ('0.000123456700', TRUNCATE, 100, SIGNIFICANT_DIGITS) === '0.0001234567');
assert (decimal_to_precision ('0.0001234567', TRUNCATE, 100, SIGNIFICANT_DIGITS) === '0.0001234567');
assert (decimal_to_precision ('0.0001234567', TRUNCATE, 7, SIGNIFICANT_DIGITS) === '0.0001234567');

assert (decimal_to_precision ('0.000123456', TRUNCATE, 6, SIGNIFICANT_DIGITS) === '0.000123456');
assert (decimal_to_precision ('0.000123456', TRUNCATE, 5, SIGNIFICANT_DIGITS) === '0.00012345');
assert (decimal_to_precision ('0.000123456', TRUNCATE, 2, SIGNIFICANT_DIGITS) === '0.00012');
assert (decimal_to_precision ('0.000123456', TRUNCATE, 1, SIGNIFICANT_DIGITS) === '0.0001');

assert (decimal_to_precision ('123.0000987654', TRUNCATE, 10, SIGNIFICANT_DIGITS) === '123.0000987');
assert (decimal_to_precision ('123.0000987654', TRUNCATE, 8, SIGNIFICANT_DIGITS) === '123.00009');
assert (decimal_to_precision ('123.0000987654', TRUNCATE, 7, SIGNIFICANT_DIGITS) === '123');
assert (decimal_to_precision ('123.0000987654', TRUNCATE, 7, SIGNIFICANT_DIGITS, PAD_WITH_ZERO) === '123.0000');
assert (decimal_to_precision ('123.0000987654', TRUNCATE, 4, SIGNIFICANT_DIGITS, PAD_WITH_ZERO) === '123.0');

assert (decimal_to_precision ('123.0000987654', TRUNCATE, 2, SIGNIFICANT_DIGITS) === '120');
assert (decimal_to_precision ('123.0000987654', TRUNCATE, 1, SIGNIFICANT_DIGITS) === '100');
assert (decimal_to_precision ('123.0000987654', TRUNCATE, 1, SIGNIFICANT_DIGITS, PAD_WITH_ZERO) === '100');

assert (decimal_to_precision ('0', TRUNCATE, 0, SIGNIFICANT_DIGITS) === '0');

// ----------------------------------------------------------------------------
// testDecimalToPrecisionRoundingToNDigitsAfterDot

assert (decimal_to_precision ('12.3456000', ROUND, 100, DECIMAL_PLACES) === '12.3456');
assert (decimal_to_precision ('12.3456', ROUND, 100, DECIMAL_PLACES) === '12.3456');
assert (decimal_to_precision ('12.3456', ROUND, 4, DECIMAL_PLACES) === '12.3456');
assert (decimal_to_precision ('12.3456', ROUND, 3, DECIMAL_PLACES) === '12.346');
assert (decimal_to_precision ('12.3456', ROUND, 2, DECIMAL_PLACES) === '12.35');
assert (decimal_to_precision ('12.3456', ROUND, 1, DECIMAL_PLACES) === '12.3');
assert (decimal_to_precision ('12.3456', ROUND, 0, DECIMAL_PLACES) === '12');

// assert (decimal_to_precision ('12.3456', ROUND, -1, DECIMAL_PLACES) === '10'); // not yet supported
// assert (decimal_to_precision ('123.456', ROUND, -1, DECIMAL_PLACES) === '120'); // not yet supported
// assert (decimal_to_precision ('123.456', ROUND, -2, DECIMAL_PLACES) === '100'); // not yet supported

assert (decimal_to_precision ('9.999', ROUND, 3, DECIMAL_PLACES) === '9.999');
assert (decimal_to_precision ('9.999', ROUND, 2, DECIMAL_PLACES) === '10');
assert (decimal_to_precision ('9.999', ROUND, 2, DECIMAL_PLACES, PAD_WITH_ZERO) === '10.00');
assert (decimal_to_precision ('99.999', ROUND, 2, DECIMAL_PLACES, PAD_WITH_ZERO) === '100.00');
assert (decimal_to_precision ('-99.999', ROUND, 2, DECIMAL_PLACES, PAD_WITH_ZERO) === '-100.00');

// ----------------------------------------------------------------------------
// testDecimalToPrecisionRoundingToNSignificantDigits

assert (decimal_to_precision ('0.000123456700', ROUND, 100, SIGNIFICANT_DIGITS) === '0.0001234567');
assert (decimal_to_precision ('0.0001234567', ROUND, 100, SIGNIFICANT_DIGITS) === '0.0001234567');
assert (decimal_to_precision ('0.0001234567', ROUND, 7, SIGNIFICANT_DIGITS) === '0.0001234567');

assert (decimal_to_precision ('0.000123456', ROUND, 6, SIGNIFICANT_DIGITS) === '0.000123456');
assert (decimal_to_precision ('0.000123456', ROUND, 5, SIGNIFICANT_DIGITS) === '0.00012346');
assert (decimal_to_precision ('0.000123456', ROUND, 4, SIGNIFICANT_DIGITS) === '0.0001235');
assert (decimal_to_precision ('0.00012', ROUND, 2, SIGNIFICANT_DIGITS) === '0.00012');
assert (decimal_to_precision ('0.0001', ROUND, 1, SIGNIFICANT_DIGITS) === '0.0001');

assert (decimal_to_precision ('123.0000987654', ROUND, 7, SIGNIFICANT_DIGITS) === '123.0001');
assert (decimal_to_precision ('123.0000987654', ROUND, 6, SIGNIFICANT_DIGITS) === '123');

assert (decimal_to_precision ('0.00098765', ROUND, 2, SIGNIFICANT_DIGITS) === '0.00099');
assert (decimal_to_precision ('0.00098765', ROUND, 2, SIGNIFICANT_DIGITS, PAD_WITH_ZERO) === '0.00099');

assert (decimal_to_precision ('0.00098765', ROUND, 1, SIGNIFICANT_DIGITS) === '0.001');
assert (decimal_to_precision ('0.00098765', ROUND, 10, SIGNIFICANT_DIGITS, PAD_WITH_ZERO) === '0.0009876500000');

assert (decimal_to_precision ('0.098765', ROUND, 1, SIGNIFICANT_DIGITS, PAD_WITH_ZERO) === '0.1');

assert (decimal_to_precision ('0', ROUND, 0, SIGNIFICANT_DIGITS) === '0');

// ----------------------------------------------------------------------------
// testDecimalToPrecisionNegativeNumbers

assert (decimal_to_precision ('-0.123456', TRUNCATE, 5, DECIMAL_PLACES) === '-0.12345');
assert (decimal_to_precision ('-0.123456', ROUND, 5, DECIMAL_PLACES) === '-0.12346');

// ----------------------------------------------------------------------------
// decimal_to_precision => without dot / trailing dot

assert (decimal_to_precision ('123', TRUNCATE, 0) === '123');

assert (decimal_to_precision ('123', TRUNCATE, 5, DECIMAL_PLACES) === '123');
assert (decimal_to_precision ('123', TRUNCATE, 5, DECIMAL_PLACES, PAD_WITH_ZERO) === '123.00000');

assert (decimal_to_precision ('123.', TRUNCATE, 0, DECIMAL_PLACES) === '123');
assert (decimal_to_precision ('123.', TRUNCATE, 5, DECIMAL_PLACES, PAD_WITH_ZERO) === '123.00000');

assert (decimal_to_precision ('0.', TRUNCATE, 0) === '0');
assert (decimal_to_precision ('0.', TRUNCATE, 5, DECIMAL_PLACES, PAD_WITH_ZERO) === '0.00000');

// ----------------------------------------------------------------------------
// decimal_to_precision => rounding for equidistant digits

assert (decimal_to_precision ('1.44', ROUND, 1, DECIMAL_PLACES) === '1.4');
assert (decimal_to_precision ('1.45', ROUND, 1, DECIMAL_PLACES) === '1.5');
assert (decimal_to_precision ('1.45', ROUND, 0, DECIMAL_PLACES) === '1'); // not 2

// ----------------------------------------------------------------------------
// testDecimalToPrecisionErrorHandling (todo)
//
// throws (() =>
// decimal_to_precision ('123456.789', TRUNCATE, -2, DECIMAL_PLACES),
// 'negative precision is not yet supported')
//
// throws (() =>
// decimal_to_precision ('foo'),
// "invalid number (contains an illegal character 'f')")
28 changes: 20 additions & 8 deletions python/ccxt/base/decimal_to_precision.py
Expand Up @@ -32,23 +32,31 @@ def decimal_to_precision(n, rounding_mode=ROUND, precision=None, counting_mode=D
assert counting_mode in [DECIMAL_PLACES, SIGNIFICANT_DIGITS]
assert padding_mode in [NO_PADDING, PAD_WITH_ZERO]

context = decimal.getcontext()

precision = min(context.prec - 2, precision)

# all default except decimal.Underflow (raised when a number is rounded to zero)
decimal.getcontext().traps[decimal.Underflow] = True
context.traps[decimal.Underflow] = True

dec = decimal.Decimal(n)
string = str(dec)

def quant(x):
def power_of_10(x):
return decimal.Decimal('10') ** (-x)

if rounding_mode == ROUND:
if counting_mode == DECIMAL_PLACES:
precise = str(dec.quantize(quant(precision))) # ROUND_HALF_EVEN is default context
context.rounding = decimal.ROUND_HALF_UP
precise = str(dec.quantize(power_of_10(precision))) # ROUND_HALF_EVEN is default context
context.rounding = decimal.ROUND_HALF_EVEN
elif counting_mode == SIGNIFICANT_DIGITS:
q = precision - dec.adjusted() - 1
sigfig = quant(q)
sigfig = power_of_10(q)
if q < 0:
below = sigfig * decimal.Decimal(string[:precision])
string_to_precision = string[:precision]
# string_to_precision is '' when we have zero precision
below = sigfig * decimal.Decimal(string_to_precision if string_to_precision else '0')
above = below + sigfig
precise = str(min((below, above), key=lambda x: abs(x - dec)))
else:
Expand All @@ -64,16 +72,20 @@ def quant(x):
dot = string.index('.') if '.' in string else 0
start = dot - dec.adjusted()
end = start + precision
# need to clarify these conditionals
if dot >= end:
end -= 1
if dec.adjusted() < 0:
end += 1
# not sure if we should keep this
# if dec.adjusted() < 0:
# end += 1
precise = string[:end].ljust(dot, '0')

if '.' == precise[-1]:
if '.' == (precise[-1] if precise else ''):
raise ValueError

if padding_mode == NO_PADDING:
if precise == '' and precision == 0:
return '0'
return precise.rstrip('0').rstrip('.') if '.' in precise else precise
elif padding_mode == PAD_WITH_ZERO:
if '.' in precise:
Expand Down

0 comments on commit 5ae6e9c

Please sign in to comment.