コード例 #1
0
 def test_fix_market_status_limits_with_specific(self):
     # binance specific
     market_status = {
         Ecmsc.INFO.value: {
             Ecmsic.FILTERS.value: [{
                 Ecmsic.FILTER_TYPE.value:
                 Ecmsic.PRICE_FILTER.value,
                 Ecmsic.MAX_PRICE.value:
                 123456789,
                 Ecmsic.MIN_PRICE.value:
                 0.1234567
             }, {
                 Ecmsic.FILTER_TYPE.value:
                 Ecmsic.LOT_SIZE.value,
                 Ecmsic.MAX_QTY.value:
                 9e11,
                 Ecmsic.MIN_QTY.value:
                 5e-11
             }]
         }
     }
     emsf = ExchangeMarketStatusFixer(market_status)
     emsf._fix_market_status_limits_with_specific()
     assert emsf.market_status()[Ecmsc.LIMITS.value] == self._get_limits(
         5e-11, 9e11, 0.1234567, 123456789, 5e-11 * 0.1234567,
         9e11 * 123456789)
コード例 #2
0
 def test_get_price_precision(self):
     assert ExchangeMarketStatusFixer({},
                                      10.5555)._get_price_precision() == 4
     assert ExchangeMarketStatusFixer(
         {}, 1014578587.5)._get_price_precision() == 1
     assert ExchangeMarketStatusFixer(
         {}, 1.00000000055)._get_price_precision() == 11
     assert ExchangeMarketStatusFixer({}, 1)._get_price_precision() == 0
コード例 #3
0
 def test_get_price_precision(self):
     if not os.getenv('CYTHON_IGNORE'):
         assert ExchangeMarketStatusFixer(
             {}, 10.5555)._get_price_precision() == 4
         assert ExchangeMarketStatusFixer(
             {}, 1014578587.5)._get_price_precision() == 1
         assert ExchangeMarketStatusFixer(
             {}, 1.00000000055)._get_price_precision() == 11
         assert ExchangeMarketStatusFixer({}, 1)._get_price_precision() == 0
コード例 #4
0
 def get_market_status(self, symbol, price_example=None, with_fixer=True):
     try:
         if with_fixer:
             return ExchangeMarketStatusFixer(self.client.market(symbol), price_example).market_status
         else:
             return self.client.market(symbol)
     except Exception as e:
         self.logger.error(f"Fail to get market status of {symbol}: {e}")
         return {}
コード例 #5
0
def is_valid(element, key):
    """
    Checks is the element is valid with the market status fixer
    :param element:
    :param key:
    :return:
    """
    return key in element and ExchangeMarketStatusFixer.is_ms_valid(
        element[key])
コード例 #6
0
 def get_market_status(self, symbol, price_example=None, with_fixer=True):
     try:
         # TODO remove these logs when C typing issues are fixed
         if with_fixer:
             ms = ExchangeMarketStatusFixer(self.client.market(symbol), price_example).market_status
         else:
             ms = self.client.market(symbol)
         self.logger.debug(f"get_market_status({symbol}, {price_example}, {with_fixer}): {ms}")
         return ms
     except Exception as e:
         self.logger.error(f"Fail to get market status of {symbol}: {e}")
         return {}
コード例 #7
0
    def test_exchange_market_status_fixer_without_price_amount(self):
        ms = {
            Ecmsc.PRECISION.value: self._get_precision(5, 5, 5),
            Ecmsc.LIMITS.value: self._get_limits(nan, None, 0.03, 1e4, 0.05,
                                                 1e7)
        }

        assert ExchangeMarketStatusFixer(ms).market_status() == {
            Ecmsc.PRECISION.value:
            self._get_precision(5, 5, 5),
            Ecmsc.LIMITS.value:
            self._get_limits(0.05 / 0.03, 1e7 / 1e4, 0.03, 1e4, 0.05, 1e7)
        }
コード例 #8
0
    def test_exchange_market_status_fixer_without_price(self):
        ms = {
            Ecmsc.PRECISION.value: self._get_precision(5, 5, 5),
            Ecmsc.LIMITS.value: self._get_limits(0.01, 1e3, nan, nan, 0.05,
                                                 1e5)
        }

        assert ExchangeMarketStatusFixer(ms).market_status() == {
            Ecmsc.PRECISION.value:
            self._get_precision(5, 5, 5),
            Ecmsc.LIMITS.value:
            self._get_limits(0.01, 1e3, 0.05 / 0.01, 1e5 / 1e3, 0.05, 1e5)
        }
コード例 #9
0
    def test_exchange_market_status_fixer_without_cost(self):
        ms = {
            Ecmsc.PRECISION.value: self._get_precision(5, 5, 5),
            Ecmsc.LIMITS.value: self._get_limits(0.05, 1e4, 0.01, 1e4, None,
                                                 None)
        }

        assert ExchangeMarketStatusFixer(ms).market_status() == {
            Ecmsc.PRECISION.value:
            self._get_precision(5, 5, 5),
            Ecmsc.LIMITS.value:
            self._get_limits(0.05, 1e4, 0.01, 1e4, 0.01 * 0.05, 1e4 * 1e4)
        }
コード例 #10
0
def add_dusts_to_quantity_if_necessary(quantity, price, symbol_market,
                                       current_symbol_holding):
    """
    Adds remaining quantity to the order if the remaining quantity is too small
    :param quantity:
    :param price:
    :param symbol_market:
    :param current_symbol_holding:
    :return:
    """
    remaining_portfolio_amount = float("{1:.{0}f}".format(
        CURRENCY_DEFAULT_MAX_PRICE_DIGITS, current_symbol_holding - quantity))
    remaining_max_total_order_price = remaining_portfolio_amount * price

    symbol_market_limits = symbol_market[Ecmsc.LIMITS.value]

    limit_amount = symbol_market_limits[Ecmsc.LIMITS_AMOUNT.value]
    limit_cost = symbol_market_limits[Ecmsc.LIMITS_COST.value]

    if not (is_valid(limit_amount, Ecmsc.LIMITS_AMOUNT_MIN.value)
            and is_valid(limit_cost, Ecmsc.LIMITS_COST_MIN.value)):
        fixed_market_status = ExchangeMarketStatusFixer(
            symbol_market, price).get_market_status()
        limit_amount = fixed_market_status[Ecmsc.LIMITS.value][
            Ecmsc.LIMITS_AMOUNT.value]
        limit_cost = fixed_market_status[Ecmsc.LIMITS.value][
            Ecmsc.LIMITS_COST.value]

    min_quantity = get_value_or_default(limit_amount,
                                        Ecmsc.LIMITS_AMOUNT_MIN.value,
                                        math.nan)
    min_cost = get_value_or_default(limit_cost, Ecmsc.LIMITS_COST_MIN.value,
                                    math.nan)

    # check with 40% more than remaining total not to require huge market moves to sell this asset
    min_cost_to_consider = min_cost * 1.4
    min_quantity_to_consider = min_quantity * 1.4

    if remaining_max_total_order_price < min_cost_to_consider \
            or remaining_portfolio_amount < min_quantity_to_consider:
        return current_symbol_holding
    else:
        return quantity
コード例 #11
0
    def test_exchange_market_status_fixer_without_precision_cost_and_amount_with_price(
            self):
        current_price = 4564.1458

        ms = {
            Ecmsc.PRECISION.value: self._get_precision(1, 0, 1),
            Ecmsc.LIMITS.value: self._get_limits(None, nan, 0.05, 1e4, nan,
                                                 None)
        }

        assert ExchangeMarketStatusFixer(
            ms, price_example=current_price).market_status() == {
                Ecmsc.PRECISION.value:
                self._get_precision(1, 0, 1),
                Ecmsc.LIMITS.value:
                self._get_limits(0.002190990480628382, 219.0990480628382,
                                 current_price / 1000, current_price * 1000,
                                 0.010000000000000012, 1000000000.0000011)
            }

        ms = {
            Ecmsc.PRECISION.value: self._get_precision(nan, None, nan),
            Ecmsc.LIMITS.value: self._get_limits(None, nan, 0.05, 1e4, nan,
                                                 None)
        }

        assert ExchangeMarketStatusFixer(
            ms, price_example=current_price).market_status() == {
                Ecmsc.PRECISION.value:
                self._get_precision(4, 4, 4),
                Ecmsc.LIMITS.value:
                self._get_limits(0.002190990480628382, 219.0990480628382,
                                 current_price / 1000, current_price * 1000,
                                 0.010000000000000012, 1000000000.0000011)
            }

        current_price = 1.56e-6
        ms = {
            Ecmsc.PRECISION.value: self._get_precision(nan, None, nan),
            Ecmsc.LIMITS.value: self._get_limits(None, nan, None, None, nan,
                                                 None)
        }

        assert ExchangeMarketStatusFixer(
            ms, price_example=current_price).market_status() == {
                Ecmsc.PRECISION.value:
                self._get_precision(8, 8, 8),
                Ecmsc.LIMITS.value:
                self._get_limits(641.0256410256403, 6410256.4102564035,
                                 current_price / 1000, current_price * 1000,
                                 9.999999999999991e-07, 9999.99999999999)
            }

        current_price = 1.5678999
        ms = {
            Ecmsc.PRECISION.value: self._get_precision(nan, None, nan),
            Ecmsc.LIMITS.value: self._get_limits(None, nan, 0, 0, nan, None)
        }

        assert ExchangeMarketStatusFixer(
            ms, price_example=current_price).market_status() == {
                Ecmsc.PRECISION.value:
                self._get_precision(7, 7, 7),
                Ecmsc.LIMITS.value:
                self._get_limits(6.37795818470299, 637795.8184702988,
                                 current_price / 1000, current_price * 1000,
                                 0.01, 999999999.9999996)
            }

        current_price = 25.87257
        ms = {
            Ecmsc.PRECISION.value: self._get_precision(),
            Ecmsc.LIMITS.value: self._get_limits(None, None, 0, 0, None, None)
        }

        assert ExchangeMarketStatusFixer(
            ms, price_example=current_price).market_status() == {
                Ecmsc.PRECISION.value:
                self._get_precision(5, 5, 5),
                Ecmsc.LIMITS.value:
                self._get_limits(0.3865097282566056, 38650.97282566052,
                                 current_price / 1000, current_price * 1000,
                                 0.010000000000000007, 999999999.9999996)
            }

        current_price = 200.555
        ms = {
            Ecmsc.PRECISION.value: self._get_precision(nan, nan, nan),
            Ecmsc.LIMITS.value: self._get_limits(nan, nan, 3, 3, nan, nan)
        }

        assert ExchangeMarketStatusFixer(
            ms, price_example=current_price).market_status() == {
                Ecmsc.PRECISION.value:
                self._get_precision(3, 3, 3),
                Ecmsc.LIMITS.value:
                self._get_limits(0.04986163396574511, 4986.163396574511,
                                 current_price / 1000, current_price * 1000,
                                 0.01000000000000001, 1000000000.0000011)
            }
コード例 #12
0
    def test_fix_market_status_precision_with_price(self):
        emsf = ExchangeMarketStatusFixer({}, 10234.55)
        emsf._fix_market_status_precision_with_price()
        assert emsf.market_status()[
            Ecmsc.PRECISION.value] == self._get_precision(2, 2, 2)

        emsf = ExchangeMarketStatusFixer({}, 10234)
        emsf._fix_market_status_precision_with_price()
        assert emsf.market_status()[
            Ecmsc.PRECISION.value] == self._get_precision(0, 0, 0)

        emsf = ExchangeMarketStatusFixer({}, 10.234140561412567)
        emsf._fix_market_status_precision_with_price()
        assert emsf.market_status()[
            Ecmsc.PRECISION.value] == self._get_precision(15, 15, 15)
コード例 #13
0
    def test_fix_market_status_limits_with_price(self):
        emsf = ExchangeMarketStatusFixer({}, 98765)
        emsf._fix_market_status_limits_with_price()
        assert emsf.market_status()[Ecmsc.LIMITS.value] == self._get_limits(
            0.00010125044297068805, 10.125044297068806, 98.765, 98765000,
            0.010000000000000005, 1000000000.0000006)

        emsf = ExchangeMarketStatusFixer({}, 0.00123456)
        emsf._fix_market_status_limits_with_price()
        assert emsf.market_status()[Ecmsc.LIMITS.value] == self._get_limits(
            0.8100051840331779, 8100.051840331779, 1.23456e-06, 1.23456,
            1.0000000000000002e-06, 10000.000000000002)

        emsf = ExchangeMarketStatusFixer({}, 0.0000012)
        emsf._fix_market_status_limits_with_price()
        assert emsf.market_status()[Ecmsc.LIMITS.value] == self._get_limits(
            833.3333333333311, 8333333.333333311, 1.2e-9, 0.0012,
            9.999999999999974e-07, 9999.999999999973)

        emsf = ExchangeMarketStatusFixer({}, 0.000999)
        emsf._fix_market_status_limits_with_price()
        assert emsf.market_status()[Ecmsc.LIMITS.value] == self._get_limits(
            1.001001001001, 10010.010010009999, 9.99e-07, 0.9990000000000001,
            9.999999999999991e-07, 9999.99999999999)
コード例 #14
0
def check_and_adapt_order_details_if_necessary(quantity,
                                               price,
                                               symbol_market,
                                               fixed_symbol_data=False):
    """
    Checks if order attributes are valid and try to fix it if not
    :param quantity:
    :param price:
    :param symbol_market:
    :param fixed_symbol_data:
    :return:
    """
    symbol_market_limits = symbol_market[Ecmsc.LIMITS.value]

    limit_amount = symbol_market_limits[Ecmsc.LIMITS_AMOUNT.value]
    limit_cost = symbol_market_limits[Ecmsc.LIMITS_COST.value]
    limit_price = symbol_market_limits[Ecmsc.LIMITS_PRICE.value]

    # case 1: try with data directly from exchange
    if is_valid(limit_amount, Ecmsc.LIMITS_AMOUNT_MIN.value):
        min_quantity = get_value_or_default(limit_amount,
                                            Ecmsc.LIMITS_AMOUNT_MIN.value,
                                            math.nan)
        max_quantity = None
        # not all symbol data have a max quantity
        if is_valid(limit_amount, Ecmsc.LIMITS_AMOUNT_MAX.value):
            max_quantity = get_value_or_default(limit_amount,
                                                Ecmsc.LIMITS_AMOUNT_MAX.value,
                                                math.nan)

        # adapt digits if necessary
        valid_quantity = adapt_quantity(symbol_market, quantity)
        valid_price = adapt_price(symbol_market, price)

        total_order_price = valid_quantity * valid_price

        if valid_quantity < min_quantity:
            # invalid order
            return []

        # case 1.1: use only quantity and cost
        if is_valid(limit_cost, Ecmsc.LIMITS_COST_MIN.value):
            min_cost = get_value_or_default(limit_cost,
                                            Ecmsc.LIMITS_COST_MIN.value,
                                            math.nan)
            max_cost = None
            # not all symbol data have a max cost
            if is_valid(limit_cost, Ecmsc.LIMITS_COST_MAX.value):
                max_cost = get_value_or_default(limit_cost,
                                                Ecmsc.LIMITS_COST_MAX.value,
                                                math.nan)

            # check total_order_price not < min_cost
            if not check_cost(total_order_price, min_cost):
                return []

            # check total_order_price not > max_cost and valid_quantity not > max_quantity
            elif (max_cost is not None and total_order_price > max_cost) or \
                    (max_quantity is not None and valid_quantity > max_quantity):
                # split quantity into smaller orders
                return split_orders(total_order_price, max_cost,
                                    valid_quantity, max_quantity, price,
                                    quantity, symbol_market)

            else:
                # valid order that can be handled wy the exchange
                return [(valid_quantity, valid_price)]

        # case 1.2: use only quantity and price
        elif is_valid(limit_price, Ecmsc.LIMITS_PRICE_MIN.value):
            min_price = get_value_or_default(limit_price,
                                             Ecmsc.LIMITS_PRICE_MIN.value,
                                             math.nan)
            max_price = None
            # not all symbol data have a max price
            if is_valid(limit_price, Ecmsc.LIMITS_PRICE_MAX.value):
                max_price = get_value_or_default(limit_price,
                                                 Ecmsc.LIMITS_PRICE_MAX.value,
                                                 math.nan)

            if (max_price is not None and
                (max_price <= valid_price)) or valid_price <= min_price:
                # invalid order
                return []

            # check total_order_price not > max_cost and valid_quantity not > max_quantity
            elif max_quantity is not None and valid_quantity > max_quantity:
                # split quantity into smaller orders
                return adapt_order_quantity_because_quantity(
                    valid_quantity, max_quantity, quantity, price,
                    symbol_market)
            else:
                # valid order that can be handled wy the exchange
                return [(valid_quantity, valid_price)]

    if not fixed_symbol_data:
        # case 2: try fixing data from exchanges
        fixed_data = ExchangeMarketStatusFixer(symbol_market,
                                               price).market_status
        return check_and_adapt_order_details_if_necessary(
            quantity, price, fixed_data, fixed_symbol_data=True)
    else:
        # impossible to check if order is valid: refuse it
        return []