def update_evaluator_config(new_config, deactivate_others=False): current_config = _get_evaluator_config() try: ConfigManager.update_evaluator_config(new_config, current_config, deactivate_others) return True except Exception: return False
def update_evaluator_config(new_config): current_config = _get_evaluator_config() try: ConfigManager.update_evaluator_config(new_config, current_config) return True except Exception: return False
def update_global_config(new_config, delete=False): current_edited_config = get_edited_config() ConfigManager.update_global_config(new_config, current_edited_config, update_input=True, delete=delete) return True
def update_trading_config(new_config): current_config = _get_trading_config() try: ConfigManager.update_trading_config(new_config, current_config) return True except Exception: return False
def _check_exchange_data(self, config, found_currencies_prices): for exchange_data in self._previous_state.values(): # check currencies missing_traded_currencies = set() for currency in exchange_data[ WATCHED_MARKETS_INITIAL_STARTUP_VALUES].keys(): if currency in found_currencies_prices: found_currencies_prices[currency] = True else: missing_traded_currencies.add(currency) if missing_traded_currencies: self.logger.warning( f"{self.ERROR_MESSAGE}Missing trading pair(s) for " f"{', '.join(missing_traded_currencies)}.") return False # check reference market if exchange_data[REFERENCE_MARKET] != config[CONFIG_TRADING][ CONFIG_TRADER_REFERENCE_MARKET]: self.logger.warning( f"{self.ERROR_MESSAGE}Reference market changed, " f"reinitializing traders.") return False # check initial portfolios and portfolios values if ConfigManager.get_trader_simulator_enabled(config): if exchange_data[SIMULATOR_INITIAL_STARTUP_PORTFOLIO] is None \ or exchange_data[SIMULATOR_INITIAL_STARTUP_PORTFOLIO_VALUE] is None: return False if ConfigManager.get_trader_enabled(config): if exchange_data[REAL_INITIAL_STARTUP_PORTFOLIO] is None\ or exchange_data[REAL_INITIAL_STARTUP_PORTFOLIO_VALUE] is None: return False return True
def _get_bot_metrics(self): return { MetricsFields.ID.value: self.bot_id, MetricsFields.CURRENT_SESSION.value: { MetricsFields.STARTED_AT.value: int(self.octobot.start_time), MetricsFields.UP_TIME.value: int(time.time() - self.octobot.start_time), MetricsFields.SIMULATOR.value: ConfigManager.get_trader_simulator_enabled(self.edited_config), MetricsFields.TRADER.value: ConfigManager.get_trader_enabled(self.edited_config), MetricsFields.EVAL_CONFIG.value: self._get_eval_config(), MetricsFields.PAIRS.value: self._get_traded_pairs(), MetricsFields.EXCHANGES.value: list(self.octobot.get_exchanges_list().keys()), MetricsFields.NOTIFICATIONS.value: self._get_notification_types(), MetricsFields.TYPE.value: get_octobot_type(), MetricsFields.PLATFORM.value: get_current_platform() } }
def reset_config_to_default(tentacle_name): try: klass, _, _ = get_tentacle_from_string(tentacle_name, with_info=False) ConfigManager.factory_reset_tentacle_config(klass) return True, f"{tentacle_name} configuration reset to default values" except Exception as e: LOGGER.exception(e) return False, f"Error when resetting factory tentacle config: {e}"
def update_tentacle_config(tentacle_name, config_update): try: klass, _, _ = get_tentacle_from_string(tentacle_name, with_info=False) ConfigManager.update_tentacle_config(klass, config_update) return True, f"{tentacle_name} updated" except Exception as e: LOGGER.exception(e) return False, f"Error when updating tentacle config: {e}"
def manage_metrics(enable_metrics): current_edited_config = get_edited_config() if CONFIG_METRICS not in current_edited_config: current_edited_config[CONFIG_METRICS] = {CONFIG_ENABLED_OPTION: enable_metrics} else: current_edited_config[CONFIG_METRICS][CONFIG_ENABLED_OPTION] = enable_metrics if enable_metrics and MetricsManager.should_register_bot(current_edited_config): MetricsManager.background_get_id_and_register_bot(get_bot()) ConfigManager.simple_save_config_update(current_edited_config)
def __init__(self, octobot): self.octobot = octobot self.edited_config = octobot.edited_config self.enabled = ConfigManager.get_metrics_enabled(self.edited_config) self.bot_id = self._init_config_bot_id(self.edited_config) self.reference_market = ConfigManager.get_reference_market( self.edited_config) self.logger = get_logger(self.__class__.__name__) self.current_config = None self.keep_running = True self.session = octobot.get_aiohttp_session() self.has_real_trader = ConfigManager.get_trader_enabled( self.edited_config)
def _get_bot_metrics(self): return { MetricsFields.ID.value: self.bot_id, MetricsFields.CURRENT_SESSION.value: { MetricsFields.STARTED_AT.value: int(self.octobot.start_time), MetricsFields.UP_TIME.value: int(time.time() - self.octobot.start_time), MetricsFields.SIMULATOR.value: ConfigManager.get_trader_simulator_enabled(self.edited_config), MetricsFields.TRADER.value: self.has_real_trader, MetricsFields.EVAL_CONFIG.value: self._get_eval_config(), MetricsFields.PAIRS.value: self._get_traded_pairs(), MetricsFields.EXCHANGES.value: list(self.octobot.get_exchanges_list().keys()), MetricsFields.NOTIFICATIONS.value: self._get_notification_types(), MetricsFields.TYPE.value: get_octobot_type(), MetricsFields.PLATFORM.value: get_current_platform(), MetricsFields.REFERENCE_MARKET.value: self.reference_market, MetricsFields.PORTFOLIO_VALUE.value: self._get_real_portfolio_value(), MetricsFields.PROFITABILITY.value: self._get_profitability() } }
def create_client(self): if self.exchange_manager.ignore_config or self.exchange_manager.check_config( self.get_name()): try: if self.exchange_manager.ignore_config or not self.exchange_manager.should_decrypt_token( self.logger): key = "" secret = "" password = "" else: config_exchange = self.config[CONFIG_EXCHANGES][self.name] key = decrypt(config_exchange[CONFIG_EXCHANGE_KEY]) secret = decrypt(config_exchange[CONFIG_EXCHANGE_SECRET]) password = decrypt(config_exchange[CONFIG_EXCHANGE_PASSWORD]) \ if CONFIG_EXCHANGE_PASSWORD in config_exchange and \ not ConfigManager.has_invalid_default_config_value(config_exchange[CONFIG_EXCHANGE_PASSWORD]) \ else None self.client = self.exchange_type({ 'apiKey': key, 'secret': secret, 'password': password, 'verbose': False, 'enableRateLimit': True }) except Exception as e: self.exchange_manager.handle_token_error(e, self.logger) self.client = self.exchange_type({'verbose': False}) else: self.client = self.exchange_type({'verbose': False}) self.logger.error( "configuration issue: missing login information !") self.client.logger.setLevel(logging.INFO)
def __init__(self, config, trader): super().__init__() self.config = config self.trader = trader self.portfolio = trader.get_portfolio() self.exchange = trader.get_exchange() self.logger = get_logger( f"{self.__class__.__name__}[{self.exchange.get_name()}]") self.trade_history = [] self.profitability = 0 self.profitability_percent = 0 self.profitability_diff = 0 self.currencies_last_prices = {} self.origin_crypto_currencies_values = {} self.current_crypto_currencies_values = {} self.origin_portfolio = None # buffer of currencies excluding market only used currencies ex: conf = btc/usd, eth/btc, ltc/btc, here usd # is market only => not used to compute market average profitability self.traded_currencies_without_market_specific = set() # buffer of currencies containing currencies that have already been logged as without matching symbol # (used not to spam logs) self.already_informed_no_matching_symbol_currency = set() self.portfolio_origin_value = 0 self.portfolio_current_value = 0 self.trades_value = 0 self.reference_market = ConfigManager.get_reference_market(self.config)
def _load_previous_state_metadata(self, target_exchanges, config): if path.isfile(self.save_file): try: potential_previous_state = load_config(self.save_file) if isinstance(potential_previous_state, dict): if not self._check_required_values( potential_previous_state): return False # check data found_currencies_prices = { currency: False for currency in ConfigManager.get_all_currencies( config) } if not self._check_exchange_data(config, found_currencies_prices): return False if not self._check_missing_symbols( found_currencies_prices): return False if not self._check_no_missing_exchanges(target_exchanges): return False except Exception as e: self.logger.warning(f"{self.ERROR_MESSAGE}{e}") return False return True else: return False
def _log_terms_if_unaccepted(config, logger): if not ConfigManager.accepted_terms(config): logger.info("*** Disclaimer ***") for line in DISCLAIMER: logger.info(line) logger.info("... Disclaimer ...") else: logger.info("Disclaimer accepted by user.")
def _load_previous_state(self, target_exchanges, config): if self._load_previous_state_metadata(target_exchanges, config): if ConfigManager.get_trader_simulator_enabled(config): return self._load_previous_state_portfolios(target_exchanges) else: return True else: return False
def should_decrypt_token(self, logger): if ConfigManager.has_invalid_default_config_value( self.config[CONFIG_EXCHANGES][self.get_exchange_name()][CONFIG_EXCHANGE_KEY], self.config[CONFIG_EXCHANGES][self.get_exchange_name()][CONFIG_EXCHANGE_SECRET]): logger.warning("Exchange configuration tokens are not set yet, to use OctoBot's real trader's features, " "please enter your api tokens in exchange configuration") return False return True
def get_reference_market(): global reference_market if reference_market is None: try: reference_market = ConfigManager.get_reference_market( global_config) except StopIteration: reference_market = None return reference_market
async def sell_all_currencies(self): orders = [] for currency in self.portfolio.get_portfolio(): symbol, inverted = ConfigManager.get_market_pair(self.config, currency) if symbol: orders += await self.sell_everything(symbol, inverted) await AbstractTradingModeDecider.push_order_notification_if_possible(orders, self.notifier) return orders
def install_on_development(config, module_dev): # is not on development if module_dev is None or not module_dev: return True # is on development if module_dev and ConfigManager.is_in_dev_mode(config): return True return False
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, config, source, files=None, reset_tentacle_config=False): if files is None: files = [] backtester_config = config if reset_tentacle_config: backtester_config = ConfigManager.reload_tentacle_config(copy(config)) self.octobot, self.ignored_files = get_standalone_backtesting_bot(backtester_config, files) self.error = None self._source = source self.finished_source = None self.errors_count = None
async def eval(self) -> None: try: self.ensure_eval_note_is_not_expired() await self.eval_impl() except Exception as e: if ConfigManager.is_in_dev_mode(self.config): raise e else: self.logger.error("Exception in eval_impl(): " + str(e)) finally: if self.eval_note == "nan": self.eval_note = START_PENDING_EVAL_NOTE self.logger.warning(str(self.symbol) + " evaluator returned 'nan' as eval_note, ignoring this value.")
def _get_symbol_list(self): self.symbols = [] self.data = {} symbols_appended = {} relevant_symbols = set(ConfigManager.get_symbols(self.config)) # parse files for file in self.config[CONFIG_BACKTESTING][CONFIG_BACKTESTING_DATA_FILES]: exchange_name, symbol, timestamp, data_type = interpret_file_name(file) if symbol is not None and symbol in relevant_symbols: if exchange_name is not None and timestamp is not None and data_type is not None: # check if symbol data already in symbols # TODO check exchanges ? if symbol not in symbols_appended: symbols_appended[symbol] = 0 if symbols_appended[symbol] < int(timestamp): symbols_appended[symbol] = int(timestamp) self.symbols.append(symbol) data = DataCollectorParser.parse(file) self.data[symbol] = self.fix_timestamps(data)
def start_octobot(starting_args): try: fileConfig(LOGGING_CONFIG_FILE) except KeyError: print("Error when loading logging config file, it might be missing or is corrupted. File is: " + LOGGING_CONFIG_FILE) logger = logging.getLogger("OctoBot Launcher") # Force new log file creation not to log at the previous one's end. try: logger.parent.handlers[1].doRollover() except IndexError: print("Logfile rotation disabled: error when handling logging config.") sys.excepthook = _log_uncaught_exceptions try: if starting_args.version: print(LONG_VERSION) else: # Version logger.info("Version : {0}".format(LONG_VERSION)) _check_public_announcements(logger) logger.info("Loading config files...") # configuration loading config = load_config(error=False, fill_missing_fields=True) if config is None and is_config_empty_or_missing(): logger.info("No configuration found creating default...") init_config() config = load_config(error=False) else: is_valid, e = ConfigManager.validate_config_file(config=config) if not is_valid: logger.error("OctoBot can't repair your config.json file: invalid format: " + str(e)) raise ConfigError ConfigManager.config_health_check(config) if config is None: raise ConfigError # Set Tentacle package manager current working directory TentaclePathHandler.set_tentacle_parent_directory(PROJECT_ROOT_DIR) # Handle utility methods before bot initializing if possible if starting_args.packager: Commands.package_manager(config, starting_args.packager) elif starting_args.creator: Commands.tentacle_creator(config, starting_args.creator) elif starting_args.encrypter: Commands.exchange_keys_encrypter() else: if not tentacles_arch_exists(): logger.info("No tentacles found. Installing default tentacles ...") Commands.package_manager(config, ["install", "all"], force=True) ConfigManager.reload_tentacle_config(config) if starting_args.data_collector: Commands.data_collector(config) elif starting_args.strategy_optimizer: Commands.start_strategy_optimizer(config, starting_args.strategy_optimizer) else: # In those cases load OctoBot from core.octobot import OctoBot from interfaces.bots.telegram.bot import TelegramApp from services import WebService TelegramApp.enable(config, not starting_args.no_telegram) WebService.enable(config, not starting_args.no_web) update_config_with_args(starting_args, config) reset_trading_history = starting_args.reset_trading_history bot = OctoBot(config, reset_trading_history=reset_trading_history) _log_terms_if_unaccepted(config, logger) import interfaces interfaces.__init__(bot, config) if not starting_args.no_open_web and not starting_args.no_web: Thread(target=_auto_open_web, args=(config, bot)).start() # set debug_mode = True to activate asyncio debug mode debug_mode = ConfigManager.is_in_dev_mode(config) or FORCE_ASYNCIO_DEBUG_OPTION asyncio.run(Commands.start_bot(bot, logger), debug=debug_mode) except ConfigError: logger.error("OctoBot can't start without " + CONFIG_FILE + " configuration file." + "\nYou can use " + DEFAULT_CONFIG_FILE + " as an example to fix it.") os._exit(-1) except ModuleNotFoundError as e: if 'tentacles' in str(e): logger.error("Impossible to start OctoBot, tentacles are missing.\nTo install tentacles, " "please use the following command:\nstart.py -p install all") else: logger.exception(e) os._exit(-1) except ConfigEvaluatorError: logger.error("OctoBot can't start without a valid " + CONFIG_EVALUATOR_FILE_PATH + " configuration file.\nThis file is generated on tentacle " "installation using the following command:\nstart.py -p install all") os._exit(-1) except ConfigTradingError: logger.error("OctoBot can't start without a valid " + CONFIG_TRADING_FILE_PATH + " configuration file.\nThis file is generated on tentacle " "installation using the following command:\nstart.py -p install all") os._exit(-1)
async def cancel_all_open_orders_with_currency(self, currency): symbols = ConfigManager.get_pairs(self.config, currency) if symbols: for symbol in symbols: await self.cancel_open_orders(symbol)
def _save_bot_id(self): if CONFIG_METRICS not in self.edited_config or not self.edited_config[ CONFIG_METRICS]: self.edited_config[CONFIG_METRICS] = {CONFIG_ENABLED_OPTION: True} self.edited_config[CONFIG_METRICS][CONFIG_METRICS_BOT_ID] = self.bot_id ConfigManager.simple_save_config_update(self.edited_config)
def _save_edition(): ConfigManager.simple_save_config_update(_get_config()) return True
def enabled(config): return ConfigManager.get_trader_simulator_enabled(config)
def _save_edition(): to_save_config = copy.copy(_get_config()) ConfigManager.remove_loaded_only_element(to_save_config) ConfigManager.save_config(CONFIG_FILE, to_save_config, TEMP_RESTORE_CONFIG_FILE) return True