def get_all_currencies(config): currencies = set() for symbol in ConfigManager.get_symbols(config): quote, base = split_symbol(symbol) currencies.add(quote) currencies.add(base) return currencies
def get_trade_fee( self, symbol, order_type, quantity, price, taker_or_maker=ExchangeConstantsMarketPropertyColumns.TAKER.value): symbol_fees = self.get_fees(symbol) rate = symbol_fees[ taker_or_maker] / 100 # /100 because rate in used in % currency, market = split_symbol(symbol) fee_currency = currency precision = self.get_market_status(symbol)[ExchangeConstantsMarketStatusColumns.PRECISION.value] \ [ExchangeConstantsMarketStatusColumns.PRECISION_PRICE.value] cost = float(round_into_str_with_max_digits(quantity * rate, precision)) if order_type == OrderConstants.TraderOrderTypeClasses[TraderOrderType.SELL_MARKET] \ or order_type == OrderConstants.TraderOrderTypeClasses[TraderOrderType.SELL_LIMIT]: cost = float( round_into_str_with_max_digits(cost * price, precision)) fee_currency = market return { FeePropertyColumns.TYPE.value: taker_or_maker, FeePropertyColumns.CURRENCY.value: fee_currency, FeePropertyColumns.RATE.value: rate, FeePropertyColumns.COST.value: cost }
def init_traded_currencies_without_market_specific(self): for cryptocurrency in self.config[CONFIG_CRYPTO_CURRENCIES]: for pair in self.exchange.get_exchange_manager().get_traded_pairs( cryptocurrency): symbol, _ = split_symbol(pair) if symbol not in self.traded_currencies_without_market_specific: self.traded_currencies_without_market_specific.add(symbol)
def get_standalone_backtesting_bot(config, data_files): config_to_use = create_blank_config_using_loaded_one(config) config_to_use[CONFIG_CRYPTO_CURRENCIES] = {} config_to_use[CONFIG_BACKTESTING][CONFIG_BACKTESTING_DATA_FILES] = [] # do not activate web interface on standalone backtesting bot WebService.enable(config_to_use, False) ignored_files = [] reference_market = _get_reference_market(data_files) if DEFAULT_REFERENCE_MARKET != reference_market: _switch_reference_market(config_to_use, reference_market) if data_files: for data_file_to_use in data_files: _, file_symbol, _ = interpret_file_name(data_file_to_use) currency, _ = split_symbol(file_symbol) full_file_path = CONFIG_DATA_COLLECTOR_PATH + data_file_to_use full_file_path += full_file_path if not full_file_path.endswith( DATA_FILE_EXT) else "" if currency not in config_to_use[CONFIG_CRYPTO_CURRENCIES]: config_to_use[CONFIG_CRYPTO_CURRENCIES][currency] = { CONFIG_CRYPTO_PAIRS: [] } if file_symbol not in config_to_use[CONFIG_CRYPTO_CURRENCIES][ currency][CONFIG_CRYPTO_PAIRS]: config_to_use[CONFIG_CRYPTO_CURRENCIES][currency][ CONFIG_CRYPTO_PAIRS].append(file_symbol) config_to_use[CONFIG_BACKTESTING][ CONFIG_BACKTESTING_DATA_FILES].append(full_file_path) else: ignored_files.append(data_file_to_use) return create_backtesting_bot(config_to_use), ignored_files
async def create_order(self, order_data, current_price, symbol_market, trader, portfolio): created_order = None currency, market = split_symbol(order_data.symbol) try: for order_quantity, order_price in self.check_and_adapt_order_details_if_necessary( order_data.quantity, order_data.price, symbol_market): selling = order_data.side == TradeOrderSide.SELL if selling: if portfolio.get_portfolio()[currency][ Portfolio.AVAILABLE] < order_quantity: return None elif portfolio.get_portfolio()[market][ Portfolio.AVAILABLE] < order_quantity * order_price: return None order_type = TraderOrderType.SELL_LIMIT if selling else TraderOrderType.BUY_LIMIT created_order = trader.create_order_instance( order_type=order_type, symbol=order_data.symbol, current_price=current_price, quantity=order_quantity, price=order_price) await trader.create_order(created_order, portfolio) except InsufficientFunds as e: raise e except Exception as e: self.logger.error( f"Failed to create order : {e}. " f"Order: " f"{created_order.get_string_info() if created_order else None}" ) self.logger.exception(e) return None return created_order
def _evaluate_config_crypto_currencies_values(self): values_dict = {} for crypto_currency_data in self.config[CONFIG_CRYPTO_CURRENCIES].values(): pairs = crypto_currency_data[CONFIG_CRYPTO_PAIRS] if pairs: currency, _ = split_symbol(pairs[0]) values_dict[currency] = self._evaluate_value(currency, 1) return values_dict
def __init__(self, trading_mode, symbol_evaluator, exchange): super().__init__(trading_mode, symbol_evaluator, exchange) self.volume_weight = self.price_weight = self.last_buy_candle = None self.last_buy_candle = {self.SIMUALTOR_KEY: None, self.REAL_KEY: None} self.first_trigger = True self.sell_targets_by_order = {} self.quote, _ = split_symbol(self.symbol) self.sell_orders_per_buy = self.trading_mode.get_trading_config_value( "sell_orders_count")
def get_currency_graph_update(exchange_name, symbol, time_frame, cryptocurrency_name): symbol_evaluator_list = get_bot().get_symbol_evaluator_list() exchange_list = get_bot().get_exchanges_list() if time_frame is not None: if len(symbol_evaluator_list) > 0: evaluator_thread_managers = symbol_evaluator_list[symbol].get_evaluator_thread_managers( exchange_list[exchange_name]) if time_frame in evaluator_thread_managers: evaluator_thread_manager = evaluator_thread_managers[time_frame] data = evaluator_thread_manager.get_evaluator().get_data() if data is not None: _, pair_tag = split_symbol(symbol) add_to_symbol_data_history(symbol, data, time_frame) data = get_symbol_data_history(symbol, time_frame) # data.loc[:, PriceStrings.STR_PRICE_TIME.value] /= 1000 data_x = data[PriceIndexes.IND_PRICE_TIME.value] data_y = data[PriceIndexes.IND_PRICE_CLOSE.value] # Candlestick ohlc_graph = go.Ohlc(x=data[PriceIndexes.IND_PRICE_TIME.value], open=data[PriceIndexes.IND_PRICE_OPEN.value], high=data[PriceIndexes.IND_PRICE_HIGH.value], low=data[PriceIndexes.IND_PRICE_LOW.value], close=data[PriceIndexes.IND_PRICE_CLOSE.value]) real_trades_prices, real_trades_times, simulated_trades_prices, simulated_trades_times = \ get_trades_by_times_and_prices() real_trades_points = go.Scatter( x=real_trades_prices, y=real_trades_times, mode='markers', name='markers' ) simulated_trades_points = go.Scatter( x=simulated_trades_times, y=simulated_trades_prices, mode='markers', name='markers' ) return {'data': [ohlc_graph, real_trades_points, simulated_trades_points], 'layout': go.Layout( title="{} real time data (per time frame)".format(cryptocurrency_name), xaxis=dict(range=[min(data_x), max(data_x)], title=TIME_AXIS_TITLE), yaxis=dict(range=[min(data_y) * 0.98, max(data_y) * 1.02], title=pair_tag) )} return None
def get_market_pair(config, currency) -> (str, bool): if CONFIG_TRADING in config: reference_market = ConfigManager.get_reference_market(config) for symbol in ConfigManager.get_symbols(config): symbol_currency, symbol_market = split_symbol(symbol) if currency == symbol_currency and reference_market == symbol_market: return symbol, False elif reference_market == symbol_currency and currency == symbol_market: return symbol, True return "", False
def _get_reference_market(data_files): reference_market = None for data_file in data_files: _, file_symbol, _, _ = interpret_file_name(data_file) currency, market = split_symbol(file_symbol) if reference_market is None: reference_market = market elif not reference_market == market: # more than one reference market in data_files: use first reference market return reference_market return reference_market if reference_market is not None else DEFAULT_REFERENCE_MARKET
def get_market_pair(config, currency) -> (str, bool): if CONFIG_TRADING in config: reference_market = get_value_or_default( config[CONFIG_TRADING], CONFIG_TRADER_REFERENCE_MARKET, DEFAULT_REFERENCE_MARKET) for symbol in ConfigManager.get_symbols(config): symbol_currency, symbol_market = split_symbol(symbol) if currency == symbol_currency and reference_market == symbol_market: return symbol, False elif reference_market == symbol_currency and currency == symbol_market: return symbol, True return "", False
async def _evaluate_config_crypto_currencies_values(self): values_dict = {} evaluated_currencies = set() for crypto_currency_data in self.config[CONFIG_CRYPTO_CURRENCIES].values(): pairs = crypto_currency_data[CONFIG_CRYPTO_PAIRS] if pairs: currency, market = split_symbol(pairs[0]) if currency not in evaluated_currencies: values_dict[currency] = await self._evaluate_value(currency, 1) evaluated_currencies.add(currency) if market not in evaluated_currencies: values_dict[market] = await self._evaluate_value(market, 1) evaluated_currencies.add(market) return values_dict
async def _evaluate_config_crypto_currencies_values(self): values_dict = {} evaluated_currencies = set() for cryptocurrency in self.config[CONFIG_CRYPTO_CURRENCIES]: pairs = self.exchange.get_exchange_manager().get_traded_pairs( cryptocurrency) if pairs: currency, market = split_symbol(pairs[0]) if currency not in evaluated_currencies: values_dict[currency] = await self.evaluate_value( currency, 1) evaluated_currencies.add(currency) if market not in evaluated_currencies: values_dict[market] = await self.evaluate_value(market, 1) evaluated_currencies.add(market) return values_dict
def test_get_market_pair(): config = load_config("tests/static/config.json") pair, inverted = ConfigManager.get_market_pair( config, config[CONFIG_TRADING][CONFIG_TRADER_REFERENCE_MARKET]) assert pair == "" assert inverted is False pair, inverted = ConfigManager.get_market_pair(config, "") assert pair == "" assert inverted is False pair, inverted = ConfigManager.get_market_pair(config, "VEN") assert pair == "VEN/BTC" assert inverted is False pair, inverted = ConfigManager.get_market_pair(config, "USDT") assert pair == "BTC/USDT" assert inverted is True pair, inverted = ConfigManager.get_market_pair(config, "XBT") assert pair == "" assert inverted is False # now change config reference market config[CONFIG_TRADING][CONFIG_TRADER_REFERENCE_MARKET] = "USDT" pair, inverted = ConfigManager.get_market_pair(config, "BTC") assert pair == "BTC/USDT" assert inverted is False pair, inverted = ConfigManager.get_market_pair(config, "VEN") assert pair == "" assert inverted is False config[CONFIG_TRADING].pop(CONFIG_TRADER_REFERENCE_MARKET) # now use config/__init__.py reference market pair, inverted = ConfigManager.get_market_pair(config, "ADA") assert pair == "ADA/BTC" assert split_symbol(pair)[1] == DEFAULT_REFERENCE_MARKET assert inverted is False config.pop(CONFIG_TRADING) pair, inverted = ConfigManager.get_market_pair(config, "ADA") assert pair == "" assert inverted is False
def __init__(self, trading_mode, symbol_evaluator, exchange, trader, creators): AbstractTradingModeDeciderWithBot.__init__(self, trading_mode, symbol_evaluator, exchange, trader, creators) Initializable.__init__(self) exchange_fees = max(exchange.get_fees(self.symbol).values()) self.LONG_THRESHOLD = -2 * exchange_fees self.SHORT_THRESHOLD = 2 * exchange_fees self.filled_creators = [] self.pending_creators = [] self.blocked_creators = [] self.currency, self.market = split_symbol(self.symbol) market_status = exchange.get_market_status(self.symbol) self.currency_max_digits = get_value_or_default(market_status[Ecmsc.PRECISION.value], Ecmsc.PRECISION_PRICE.value, CURRENCY_DEFAULT_MAX_PRICE_DIGITS) limit_cost = market_status[Ecmsc.LIMITS.value][Ecmsc.LIMITS_COST.value] self.currency_min_cost = get_value_or_default(limit_cost, Ecmsc.LIMITS_COST_MIN.value)
async def can_create_order(symbol, exchange, state, portfolio): currency, market = split_symbol(symbol) # get symbol min amount when creating order symbol_limit = exchange.get_market_status(symbol)[Ecmsc.LIMITS.value] symbol_min_amount = symbol_limit[Ecmsc.LIMITS_AMOUNT.value][Ecmsc.LIMITS_AMOUNT_MIN.value] order_min_amount = symbol_limit[Ecmsc.LIMITS_COST.value][Ecmsc.LIMITS_COST_MIN.value] # short cases => sell => need this currency if state == EvaluatorStates.VERY_SHORT or state == EvaluatorStates.SHORT: return portfolio.get_currency_portfolio(currency) > symbol_min_amount # long cases => buy => need money(aka other currency in the pair) to buy this currency elif state == EvaluatorStates.LONG or state == EvaluatorStates.VERY_LONG: return portfolio.get_currency_portfolio(market) > order_min_amount # other cases like neutral state or unfulfilled previous conditions return False
async def get_pre_order_data(exchange, symbol, portfolio): last_prices = await exchange.execute_request_with_retry(exchange.get_recent_trades(symbol)) reference_sum = sum([float(last_price["price"]) for last_price in last_prices[-ORDER_CREATION_LAST_TRADES_TO_USE:]]) reference = reference_sum / ORDER_CREATION_LAST_TRADES_TO_USE currency, market = split_symbol(symbol) current_symbol_holding = portfolio.get_currency_portfolio(currency) current_market_quantity = portfolio.get_currency_portfolio(market) market_quantity = current_market_quantity / reference price = reference symbol_market = exchange.get_market_status(symbol, with_fixer=False) return current_symbol_holding, current_market_quantity, market_quantity, price, symbol_market
def new(self, order_type, symbol, current_price, quantity, price=None, stop_price=None, status=None, order_notifier=None, order_id=None, quantity_filled=None, timestamp=None, linked_to=None, linked_portfolio=None): self.order_id = order_id self.origin_price = price self.status = status self.created_last_price = current_price self.origin_quantity = quantity self.origin_stop_price = stop_price self.symbol = symbol self.order_type = order_type self.order_notifier = order_notifier self.currency, self.market = split_symbol(symbol) self.filled_quantity = quantity_filled self.linked_to = linked_to self.linked_portfolio = linked_portfolio if timestamp is None: self.creation_time = time.time() else: # if we have a timestamp, it's a real trader => need to format timestamp if necessary self.creation_time = self.exchange.get_uniform_timestamp(timestamp) if status is None: self.status = OrderStatus.OPEN else: self.status = status if self.trader.simulate: self.filled_quantity = quantity
def get_pre_order_data(exchange, symbol, portfolio): last_prices = exchange.get_recent_trades(symbol) reference_sum = 0 for last_price in last_prices[-ORDER_CREATION_LAST_TRADES_TO_USE:]: reference_sum += float(last_price["price"]) reference = reference_sum / ORDER_CREATION_LAST_TRADES_TO_USE currency, market = split_symbol(symbol) current_symbol_holding = portfolio.get_currency_portfolio(currency) current_market_quantity = portfolio.get_currency_portfolio(market) market_quantity = current_market_quantity / reference price = reference symbol_market = exchange.get_market_status(symbol) return current_symbol_holding, current_market_quantity, market_quantity, price, symbol_market
def __init__(self, trading_mode, symbol_evaluator, exchange, trader, creators): super().__init__(trading_mode, symbol_evaluator, exchange, trader, creators) exchange_fees = max(exchange.get_fees(self.symbol)) self.LONG_THRESHOLD = -2 * exchange_fees self.SHORT_THRESHOLD = 2 * exchange_fees self.filled_creators = [] self.pending_creators = [] self.blocked_creators = [] self.currency, self.market = split_symbol(self.symbol) market_status = exchange.get_market_status(self.symbol) self.currency_max_digits = HighFrequencyModeCreator.get_value_or_default( market_status[Ecmsc.PRECISION.value], Ecmsc.PRECISION_PRICE.value, CURRENCY_DEFAULT_MAX_PRICE_DIGITS) limit_cost = market_status[Ecmsc.LIMITS.value][Ecmsc.LIMITS_COST.value] self.currency_min_cost = HighFrequencyModeCreator.get_value_or_default( limit_cost, Ecmsc.LIMITS_COST_MIN.value) self._update_available_creators()
async def create_buy_order(self, volume_weight, trader, portfolio, symbol, exchange): current_order = None try: current_symbol_holding, current_market_holding, market_quantity, price, symbol_market = \ await self.get_pre_order_data(exchange, symbol, portfolio) quote, _ = split_symbol(symbol) created_orders = [] quantity = await self._get_buy_quantity_from_weight( volume_weight, trader, market_quantity, portfolio, quote) limit_price = self.adapt_price(symbol_market, self.get_limit_price(price)) for order_quantity, order_price in self.check_and_adapt_order_details_if_necessary( quantity, limit_price, symbol_market): current_order = trader.create_order_instance( order_type=TraderOrderType.BUY_LIMIT, symbol=symbol, current_price=price, quantity=order_quantity, price=order_price) created_order = await trader.create_order( current_order, portfolio) created_orders.append(created_order) return created_orders except InsufficientFunds as e: raise e except Exception as e: self.logger.error( f"Failed to create order : {e}. Order: " f"{current_order.get_string_info() if current_order else None}" ) self.logger.exception(e) return []
async def test_evaluator_factory_with_wildcard(): btc_crypto_currency = "Bitcoin" btc_quote = "BTC" exchange = "binance" config = load_test_config() config[CONFIG_CRYPTO_CURRENCIES] = { btc_crypto_currency: { CONFIG_CRYPTO_PAIRS: CONFIG_WILDCARD, CONFIG_CRYPTO_QUOTE: btc_quote } } bot = create_bot_with_config(config) await bot.initialize() symbol_count = len( set([ symbol if split_symbol(symbol)[1] == btc_quote else None for symbol in bot.evaluator_factory.octobot.exchange_factory. exchanges_list['binance'].exchange.client.symbols ])) - 1 # -1 for 1 None (set consequence) perform_evaluator_factory_tests(bot.evaluator_factory, btc_crypto_currency, "ETH/BTC", exchange, 1, 1, symbol_count, symbol_count)
async def create_sell_orders(self, sell_orders_count, trader, portfolio, symbol, exchange, quantity, sell_weight, sell_base): current_order = None try: current_symbol_holding, current_market_holding, market_quantity, price, symbol_market = \ await self.get_pre_order_data(exchange, symbol, portfolio) quote, _ = split_symbol(symbol) created_orders = [] sell_max_quantity = min(current_symbol_holding, quantity) to_create_orders = self._generate_sell_orders( sell_orders_count, sell_max_quantity, sell_weight, sell_base, symbol_market) for order_quantity, order_price in to_create_orders: current_order = trader.create_order_instance( order_type=TraderOrderType.SELL_LIMIT, symbol=symbol, current_price=sell_base, quantity=order_quantity, price=order_price) created_order = await trader.create_order( current_order, portfolio) created_orders.append(created_order) return created_orders except InsufficientFunds as e: raise e except Exception as e: self.logger.error( f"Failed to create order : {e}. Order: " f"{current_order.get_string_info() if current_order else None}" ) self.logger.exception(e) return []
def update_starting_portfolio_if_required(config, wanted_symbol): quote, base = split_symbol(wanted_symbol) if DEFAULT_REFERENCE_MARKET != base: _switch_reference_market(config, base)
def init_traded_currencies_without_market_specific(self): for crypto_currency in self.config[CONFIG_CRYPTO_CURRENCIES].values(): for pair in crypto_currency[CONFIG_CRYPTO_PAIRS]: symbol, _ = split_symbol(pair) if symbol not in self.traded_currencies_without_market_specific: self.traded_currencies_without_market_specific.add(symbol)
def _is_tradable_with_cryptocurrency(symbol, cryptocurrency): return symbol if split_symbol(symbol)[1] == cryptocurrency else None
async def create_new_order(self, eval_note, symbol, exchange, trader, portfolio, state): current_order = None try: current_symbol_holding, current_market_holding, market_quantity, price, symbol_market = \ await self.get_pre_order_data(exchange, symbol, portfolio) quote, _ = split_symbol(symbol) created_orders = [] if state == EvaluatorStates.VERY_SHORT: quantity = self._get_market_quantity_from_risk( eval_note, trader, current_symbol_holding, quote, True) quantity = self.add_dusts_to_quantity_if_necessary( quantity, price, symbol_market, current_symbol_holding) for order_quantity, order_price in self.check_and_adapt_order_details_if_necessary( quantity, price, symbol_market): current_order = trader.create_order_instance( order_type=TraderOrderType.SELL_MARKET, symbol=symbol, current_price=order_price, quantity=order_quantity, price=order_price) await trader.create_order(current_order, portfolio) created_orders.append(current_order) return created_orders elif state == EvaluatorStates.SHORT: quantity = await self._get_sell_limit_quantity_from_risk( eval_note, trader, current_symbol_holding, portfolio, quote) quantity = self.add_dusts_to_quantity_if_necessary( quantity, price, symbol_market, current_symbol_holding) limit_price = self.adapt_price( symbol_market, price * self._get_limit_price_from_risk(eval_note, trader)) for order_quantity, order_price in self.check_and_adapt_order_details_if_necessary( quantity, limit_price, symbol_market): current_order = trader.create_order_instance( order_type=TraderOrderType.SELL_LIMIT, symbol=symbol, current_price=price, quantity=order_quantity, price=order_price) updated_limit = await trader.create_order( current_order, portfolio) created_orders.append(updated_limit) if self.USE_STOP_ORDERS: stop_price = self.adapt_price( symbol_market, price * self._get_stop_price_from_risk(trader)) current_order = trader.create_order_instance( order_type=TraderOrderType.STOP_LOSS, symbol=symbol, current_price=price, quantity=order_quantity, price=stop_price, linked_to=updated_limit) await trader.create_order(current_order, portfolio) return created_orders elif state == EvaluatorStates.NEUTRAL: pass # TODO : stop loss elif state == EvaluatorStates.LONG: quantity = self._get_buy_limit_quantity_from_risk( eval_note, trader, market_quantity, quote) quantity = quantity * await self._get_quantity_ratio( trader, portfolio, quote) limit_price = self.adapt_price( symbol_market, price * self._get_limit_price_from_risk(eval_note, trader)) for order_quantity, order_price in self.check_and_adapt_order_details_if_necessary( quantity, limit_price, symbol_market): current_order = trader.create_order_instance( order_type=TraderOrderType.BUY_LIMIT, symbol=symbol, current_price=price, quantity=order_quantity, price=order_price) await trader.create_order(current_order, portfolio) created_orders.append(current_order) return created_orders elif state == EvaluatorStates.VERY_LONG: quantity = self._get_market_quantity_from_risk( eval_note, trader, market_quantity, quote) quantity = quantity * await self._get_quantity_ratio( trader, portfolio, quote) for order_quantity, order_price in self.check_and_adapt_order_details_if_necessary( quantity, price, symbol_market): current_order = trader.create_order_instance( order_type=TraderOrderType.BUY_MARKET, symbol=symbol, current_price=order_price, quantity=order_quantity, price=order_price) await trader.create_order(current_order, portfolio) created_orders.append(current_order) return created_orders # if nothing go returned, return None return None except InsufficientFunds as e: raise e except Exception as e: self.logger.error( f"Failed to create order : {e}. " f"Order: " f"{current_order.get_string_info() if current_order else None}" ) self.logger.exception(e) return None
def get_pairs(config, currency) -> []: pairs = [] for symbol in ConfigManager.get_symbols(config): if currency in split_symbol(symbol): pairs.append(symbol) return pairs
def _create_orders(self, lower_bound, upper_bound, side, sorted_orders, portfolio, current_price, missing_orders, state): if lower_bound >= upper_bound: self.logger.warning(f"No {side} orders for {self.symbol} possible: current price beyond boundaries.") return [] orders = [] selling = side == TradeOrderSide.SELL currency, market = split_symbol(self.symbol) order_limiting_currency = currency if selling else market order_limiting_currency_amount = portfolio[order_limiting_currency][Portfolio.AVAILABLE] \ if order_limiting_currency in portfolio else 0 if state == self.NEW: # create staggered orders starting_bound = lower_bound * (1 + self.spread / 2) if selling else upper_bound * (1 - self.spread / 2) self.flat_spread = AbstractTradingModeCreator.adapt_price(self.symbol_market, current_price * self.spread) orders_count, average_order_quantity = \ self._get_order_count_and_average_quantity(current_price, selling, lower_bound, upper_bound, order_limiting_currency_amount, currency=order_limiting_currency) for i in range(orders_count): price = self._get_price_from_iteration(starting_bound, selling, i) if price is not None: quantity = self._get_quantity_from_iteration(average_order_quantity, self.mode, side, i, orders_count, price) if quantity is not None: orders.append(OrderData(side, quantity, price, self.symbol)) if not orders: self.logger.error(f"Not enough {order_limiting_currency} to create {side.name} orders. " f"For the strategy to work better, add {order_limiting_currency} funds or " f"change change the strategy settings to make less but bigger orders.") else: orders.reverse() if state == self.FILL: # complete missing orders if missing_orders: max_quant_per_order = order_limiting_currency_amount / len(missing_orders) missing_orders_around_spread = [] for missing_order_price, missing_order_side in missing_orders: if missing_order_side == side: previous_o = None following_o = None for o in sorted_orders: if previous_o is None: previous_o = o elif o.origin_price > missing_order_price: following_o = o break else: previous_o = o if previous_o.side == following_o.side: # missing order between similar orders quantity = min(DataUtil.mean([previous_o.origin_quantity, following_o.origin_quantity]), max_quant_per_order / missing_order_price) orders.append(OrderData(missing_order_side, quantity, missing_order_price, self.symbol, False)) self.logger.debug(f"Creating missing orders not around spread: {orders[-1]}") else: missing_orders_around_spread.append((missing_order_price, missing_order_side)) if missing_orders_around_spread: # missing order next to spread starting_bound = upper_bound if selling else lower_bound increment_window = self.flat_increment/2 order_limiting_currency_available_amount = \ portfolio[order_limiting_currency][Portfolio.AVAILABLE] \ if order_limiting_currency in portfolio else 0 portfolio_total = portfolio[order_limiting_currency][Portfolio.TOTAL] \ if order_limiting_currency in portfolio else 0 order_limiting_currency_amount = portfolio_total if order_limiting_currency_available_amount: orders_count, average_order_quantity = \ self._get_order_count_and_average_quantity(current_price, selling, lower_bound, upper_bound, portfolio_total, currency=order_limiting_currency) for missing_order_price, missing_order_side in missing_orders_around_spread: limiting_amount_from_this_order = order_limiting_currency_amount price = starting_bound found_order = False i = 0 while not found_order and i < orders_count: quantity = self._get_quantity_from_iteration(average_order_quantity, self.mode, side, i, orders_count, price) limiting_currency_quantity = quantity if selling else quantity / price if price is not None and limiting_amount_from_this_order > 0 and \ price-increment_window <= missing_order_price <= price+increment_window: if limiting_currency_quantity > limiting_amount_from_this_order or \ limiting_currency_quantity > order_limiting_currency_available_amount: limiting_currency_quantity = min(limiting_amount_from_this_order, order_limiting_currency_available_amount) found_order = True if limiting_currency_quantity is not None: orders.append(OrderData(side, limiting_currency_quantity, price, self.symbol, False)) self.logger.debug(f"Creating missing order around spread {orders[-1]}") price = price - self.flat_increment if selling else price + self.flat_increment limiting_amount_from_this_order -= limiting_currency_quantity i += 1 elif state == self.ERROR: self.logger.error("Impossible to create staggered orders when incompatible order are already in place. " "Cancel these orders of you want to use this trading mode.") return orders
def get_currency_price_graph_update(exchange_name, symbol, time_frame, list_arrays=True, backtesting=False): bot = get_bot() if backtesting and bot.get_tools() and bot.get_tools( )[BOT_TOOLS_BACKTESTING]: bot = bot.get_tools()[BOT_TOOLS_BACKTESTING].get_bot() symbol = parse_get_symbol(symbol) symbol_evaluator_list = bot.get_symbol_evaluator_list() in_backtesting = Backtesting.enabled(get_global_config()) or backtesting exchange = exchange_name exchange_list = bot.get_exchanges_list() if backtesting: exchanges = [key for key in exchange_list if exchange_name in key] if exchanges: exchange = exchanges[0] if time_frame is not None: if symbol_evaluator_list: evaluator_thread_managers = symbol_evaluator_list[ symbol].get_evaluator_thread_managers(exchange_list[exchange]) if time_frame in evaluator_thread_managers: evaluator_thread_manager = evaluator_thread_managers[ time_frame] data = evaluator_thread_manager.get_evaluator().get_data() if data is not None: candles_key = "candles" real_trades_key = "real_trades" simulated_trades_key = "simulated_trades" result_dict = { candles_key: [], real_trades_key: [], simulated_trades_key: [], } _, pair_tag = split_symbol(symbol) add_to_symbol_data_history(symbol, data, time_frame, in_backtesting) data = get_symbol_data_history(symbol, time_frame) data_x = convert_timestamps_to_datetime( data[PriceIndexes.IND_PRICE_TIME.value], time_format="%y-%m-%d %H:%M:%S", force_timezone=False) real_trades_history, simulated_trades_history = get_trades_history( bot, symbol) if real_trades_history: result_dict[real_trades_key] = _format_trades( real_trades_history) if real_trades_history: result_dict[simulated_trades_key] = _format_trades( simulated_trades_history) if list_arrays: result_dict[candles_key] = { PriceStrings.STR_PRICE_TIME.value: data_x, PriceStrings.STR_PRICE_CLOSE.value: data[PriceIndexes.IND_PRICE_CLOSE.value].tolist(), PriceStrings.STR_PRICE_LOW.value: data[PriceIndexes.IND_PRICE_LOW.value].tolist(), PriceStrings.STR_PRICE_OPEN.value: data[PriceIndexes.IND_PRICE_OPEN.value].tolist(), PriceStrings.STR_PRICE_HIGH.value: data[PriceIndexes.IND_PRICE_HIGH.value].tolist() } else: result_dict[candles_key] = { PriceStrings.STR_PRICE_TIME.value: data_x, PriceStrings.STR_PRICE_CLOSE.value: data[PriceIndexes.IND_PRICE_CLOSE.value], PriceStrings.STR_PRICE_LOW.value: data[PriceIndexes.IND_PRICE_LOW.value], PriceStrings.STR_PRICE_OPEN.value: data[PriceIndexes.IND_PRICE_OPEN.value], PriceStrings.STR_PRICE_HIGH.value: data[PriceIndexes.IND_PRICE_HIGH.value] } return result_dict return None