def add_dusts_to_quantity_if_necessary(quantity, price, symbol_market, current_symbol_holding): 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 (AbstractTradingModeCreator._is_valid( limit_amount, Ecmsc.LIMITS_AMOUNT_MIN.value) and AbstractTradingModeCreator._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) if remaining_max_total_order_price < min_cost or remaining_portfolio_amount < min_quantity: return current_symbol_holding else: return quantity
def get_market_status(self, symbol, price_example=None, with_fixer=True): try: if with_fixer: return ExchangeMarketStatusFixer(self.client.find_market(symbol), price_example).get_market_status() else: return self.client.find_market(symbol) except Exception as e: self.logger.error(f"Fail to get market status of {symbol}: {e}") return {}
def _is_valid(element, key): return key in element and ExchangeMarketStatusFixer.is_ms_valid( element[key])
def check_and_adapt_order_details_if_necessary(quantity, price, symbol_market, fixed_symbol_data=False): 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 AbstractTradingModeCreator._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 AbstractTradingModeCreator._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 = AbstractTradingModeCreator._adapt_quantity( symbol_market, quantity) valid_price = AbstractTradingModeCreator.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 AbstractTradingModeCreator._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 AbstractTradingModeCreator._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 AbstractTradingModeCreator._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 AbstractTradingModeCreator._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 AbstractTradingModeCreator._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 AbstractTradingModeCreator._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 AbstractTradingModeCreator \ ._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).get_market_status() return AbstractTradingModeCreator.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 []