def __init__( self, name, config=None, onAccount=None, onOrderMatched=None, onOrderPlaced=None, onMarketUpdate=None, onUpdateCallOrder=None, ontick=None, bitshares_instance=None, *args, **kwargs ): BitsharesOrderEngine.__init__(self, name, config=config, *args, **kwargs) if ontick: self.ontick += ontick if onMarketUpdate: self.onMarketUpdate += onMarketUpdate if onAccount: self.onAccount += onAccount if onOrderMatched: self.onOrderMatched += onOrderMatched if onOrderPlaced: self.onOrderPlaced += onOrderPlaced if onUpdateCallOrder: self.onUpdateCallOrder += onUpdateCallOrder # Redirect this event to also call order placed and order matched self.onMarketUpdate += self._callbackPlaceFillOrders self.assets_intersections_data = None if config: self.config = config self.assets_intersections_data = Config.assets_intersections(config) else: self.config = config = Config.get_worker_config_file(name) # What percent of balance the worker should use self.operational_percent_quote = self.worker.get('operational_percent_quote', 0) / 100 self.operational_percent_base = self.worker.get('operational_percent_base', 0) / 100 # Initial value for check_last_run decorator in dexbot/decorators.py self.last_check = datetime(1970, 1, 1) # A private logger that adds worker identify data to the LogRecord self.log = logging.LoggerAdapter( logging.getLogger('dexbot.per_worker'), { 'worker_name': name, 'account': self.worker['account'], 'market': self.worker['market'], 'is_disabled': lambda: self.disabled, }, ) self.orders_log = logging.LoggerAdapter(logging.getLogger('dexbot.orders_log'), {})
def validate_account_not_in_use(account): """ Check whether account is already used for another worker or not :param str account: bitshares account name """ workers = Config().workers_data for worker_name, worker in workers.items(): if worker['account'] == account: return False return True
def new_func(ctx, *args, **kwargs): if not os.path.isfile(ctx.obj["configfile"]): Config(path=ctx.obj['configfile']) ctx.config = yaml.safe_load(open(ctx.obj["configfile"])) # reset to default ctx.config["node"] = Config().node_list if ctx.obj.get("sortnodes"): nodelist = sort_nodes(ctx) # sort nodes if option is given ctx.config["node"] = nodelist with open(ctx.obj["configfile"], 'w') as file: yaml.dump(ctx.config, file, default_flow_style=False) return ctx.invoke(f, *args, **kwargs)
def configure(ctx): """Interactively configure dexbot.""" # Make sure the dexbot service isn't running while we do the config edits if dexbot_service_running(): click.echo("Stopping dexbot daemon") os.system('systemctl --user stop dexbot') config = Config(path=ctx.obj['configfile']) configure_dexbot(config, ctx) config.save_config() click.echo("New configuration saved") if config.get('systemd_status', 'disabled') == 'enabled': click.echo("Starting dexbot daemon") os.system("systemctl --user start dexbot")
def __init__(self, name, config=None, _account=None, _market=None, fee_asset_symbol=None, bitshares_instance=None, bitshares_bundle=None, *args, **kwargs): # BitShares instance self.bitshares = bitshares_instance or shared_bitshares_instance() # Dex instance used to get different fees for the market self.dex = Dex(self.bitshares) # Storage Storage.__init__(self, name) # Events Events.__init__(self) # Redirect this event to also call order placed and order matched self.onMarketUpdate += self._callbackPlaceFillOrders if config: self.config = config else: self.config = Config.get_worker_config_file(name) self._market = _market self._account = _account # Recheck flag - Tell the strategy to check for updated orders self.recheck_orders = False # Count of orders to be fetched from the API self.fetch_depth = 8 self.fee_asset = fee_asset_symbol # CER cache self.core_exchange_rate = None # Ticker self.ticker = self._market.ticker # Settings for bitshares instance self.bitshares.bundle = bitshares_bundle # Disabled flag - this flag can be flipped to True by a worker and will be reset to False after reset only self.disabled = False # Order expiration time in seconds self.expiration = 60 * 60 * 24 * 365 * 5 # buy/sell actions will return order id by default self.returnOrderId = 'head'
def validate_worker_name(cls, worker_name, old_worker_name=None): if old_worker_name != worker_name: worker_names = Config().workers_data.keys() # Check that the name is unique if worker_name in worker_names: return False return True return True
def handle_open_settings(self): settings_dialog = SettingsView() reconnect = settings_dialog.exec_() if reconnect: # Reinitialize config after closing the settings window self.config = Config() self.main_controller.config = self.config self.connect_to_bitshares()
def get_unique_worker_name(): """ Returns unique worker name "Worker %n", where %n is the next available index """ index = 1 workers = Config().workers_data.keys() worker_name = "Worker {0}".format(index) while worker_name in workers: worker_name = "Worker {0}".format(index) index += 1 return worker_name
def validate_worker_name(worker_name, old_worker_name=None): """ Check whether worker name is unique or not :param str worker_name: name of the new worker :param str old_worker_name: old name of the worker """ if old_worker_name != worker_name: worker_names = Config().workers_data.keys() # Check that the name is unique if worker_name in worker_names: return False return True return True
def __init__(self, sys_argv): super(App, self).__init__(sys_argv) # Init config config = Config() # Init main controller self.main_controller = MainController(config) # Init main view self.main_view = MainView(self.main_controller) # Show main view self.main_view.show()
def __init__(self, sys_argv): super(App, self).__init__(sys_argv) config = Config() bitshares_instance = BitShares(config['node']) # Wallet unlock unlock_ctrl = WalletController(bitshares_instance) if unlock_ctrl.wallet_created(): unlock_view = UnlockWalletView(unlock_ctrl) else: unlock_view = CreateWalletView(unlock_ctrl) if unlock_view.exec_(): bitshares_instance = unlock_ctrl.bitshares self.main_ctrl = MainController(bitshares_instance, config) self.main_view = MainView(self.main_ctrl) self.main_view.show() else: sys.exit()
def shell(): """ Run dexbot as a shell """ config = Config() while True: if configure_dexbot(config, True): if config['systemd_status'] == 'installed': config.save_config() # we are already installed os.system("systemctl --user restart dexbot") if config['systemd_status'] == 'install': config['systemd_status'] = 'installed' config.save_config() os.system("systemctl --user enable dexbot") os.system("systemctl --user start dexbot")
def configure(ctx): """ Interactively configure dexbot """ config = Config(path=ctx.obj['configfile']) if configure_dexbot(config): if config['systemd_status'] == 'installed': # we are already installed config.save_config() os.system("systemctl --user restart dexbot") if config['systemd_status'] == 'install': config['systemd_status'] = 'installed' config.save_config() os.system("systemctl --user enable dexbot") os.system("systemctl --user start dexbot") click.echo("New configuration saved")
def __init__(self, view, bitshares_instance, mode): self.view = view self.mode = mode self.validator = ConfigValidator(Config(), bitshares_instance or shared_bitshares_instance())
def is_account_in_use(account): workers = Config().workers_data for worker_name, worker in workers.items(): if worker['account'] == account: return True return False
def is_worker_name_valid(worker_name): worker_names = Config().workers_data.keys() # Check that the name is unique if worker_name in worker_names: return False return True
def __init__(self, view): self.config = Config() self.view = view
class SettingsController: def __init__(self, view): self.config = Config() self.view = view def add_node(self): """ Add item in the widget tree list """ item = QTreeWidgetItem(self.view.nodes_tree_widget) item.setText(0, '') item.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled | Qt.ItemIsEditable) # Scroll to the new item and activate editing self.view.nodes_tree_widget.scrollToItem(item) self.view.nodes_tree_widget.editItem(item) self.view.notification_label.setText( 'Unsaved changes detected; Node added.') def move_up(self): """ Move item up in the widget tree list """ current_index = self.view.nodes_tree_widget.indexOfTopLevelItem( self.view.nodes_tree_widget.currentItem()) # This prevents moving item out of the list if current_index > 0: # Take the item out of the widget list item = self.view.nodes_tree_widget.takeTopLevelItem(current_index) # Put item back to the list in new position self.view.root_item.insertChild(current_index - 1, item) # Keep moved item selected self.view.nodes_tree_widget.setCurrentItem(item) self.view.notification_label.setText( 'Unsaved changes detected; List order has changed.') def move_down(self): """ Move item down in the widget tree list """ current_index = self.view.nodes_tree_widget.indexOfTopLevelItem( self.view.nodes_tree_widget.currentItem()) # This prevents moving item out of the list if current_index < (self.view.root_item.childCount() - 1): # Take the item out of the widget list item = self.view.nodes_tree_widget.takeTopLevelItem(current_index) # Put item back to the list in new position self.view.root_item.insertChild(current_index + 1, item) # Keep moved item selected self.view.nodes_tree_widget.setCurrentItem(item) self.view.notification_label.setText( 'Unsaved changes detected; List order has changed.') def save_settings(self): """ Save items in the tree widget list into the config file and close window :returns int: 1 settings saved (accepted) """ nodes = [] child_count = self.view.root_item.childCount() for index in range(child_count): nodes.append(self.view.root_item.child(index).text(0)) # Send the nodes to controller to handle the save if self.save_nodes_to_config(nodes): # Close settings dialog on save self.view.accept() def remove_node(self): """ Remove item from the widget tree list """ node = self.view.nodes_tree_widget.currentItem() if node: # Delete only if node selected, index = self.view.nodes_tree_widget.indexOfTopLevelItem(node) self.view.nodes_tree_widget.takeTopLevelItem(index) self.view.notification_label.setText( 'Unsaved changes detected; Node removed.') def initialize_node_list(self, nodes=None): """ Populates Tree Widget with nodes :param nodes: List of nodes that can be applied to the widget instead of getting them from the config file. """ # Make sure there are no widgets in the list self.view.nodes_tree_widget.clear() # Get nodes from the config file if nodes is None: nodes = self.view.controller.nodes # Check for nodes, since it is possible that the config is empty if nodes: # Add nodes to the widget list for node in nodes: item = QTreeWidgetItem(self.view.nodes_tree_widget) item.setText(0, node) item.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled | Qt.ItemIsEditable) def save_nodes_to_config(self, nodes): """ Save nodes to the config file """ # Remove empty nodes before saving, this is just to make sure no empty strings end up in config file nodes = self.remove_empty_items(nodes) if nodes: self.config['node'] = nodes self.config.save_config() # Update status self.view.notification_label.setText( 'Settings successfully saved!') return True else: self.view.notification_label.setText('Can\'t save empty list') return False def restore_defaults(self): self.initialize_node_list(nodes=self.config.node_list) self.view.notification_label.setText( 'Restored default nodes. Remember to save changes!') @staticmethod def remove_empty_items(items): """ Removes empty strings from a list """ return list(filter(None, items)) @property def nodes(self): """ Returns nodes list from the config file :return: Nodes list """ return self.config.get('node')
def __init__( self, name, config=None, _account=None, _market=None, fee_asset_symbol=None, bitshares_instance=None, *args, **kwargs ): # BitShares instance self.bitshares = bitshares_instance or shared_bitshares_instance() # Dex instance used to get different fees for the market self.dex = Dex(self.bitshares) # Storage Storage.__init__(self, name) # Events Events.__init__(self) # Redirect this event to also call order placed and order matched self.onMarketUpdate += self._callbackPlaceFillOrders if config: self.config = config else: self.config = Config.get_worker_config_file(name) # Get worker's parameters from the config self.worker = config["workers"][name] self._market = _market or Market(self.worker["market"], bitshares_instance=self.bitshares) self._account = _account or Account(self.worker["account"], full=True, bitshares_instance=self.bitshares) # Recheck flag - Tell the strategy to check for updated orders self.recheck_orders = False # Count of orders to be fetched from the API self.fetch_depth = 8 # Set fee asset fee_asset_symbol = fee_asset_symbol or self.worker.get('fee_asset') if fee_asset_symbol: try: self.fee_asset = Asset(fee_asset_symbol, bitshares_instance=self.bitshares) except bitshares.exceptions.AssetDoesNotExistsException: self.fee_asset = Asset('1.3.0', bitshares_instance=self.bitshares) else: # If there is no fee asset, use BTS self.fee_asset = Asset('1.3.0', bitshares_instance=self.bitshares) # CER cache self.core_exchange_rate = None # Ticker self.ticker = self._market.ticker # Settings for bitshares instance self.bitshares.bundle = bool(self.worker.get("bundle", False)) # Disabled flag - this flag can be flipped to True by a worker and will be reset to False after reset only self.disabled = False # Order expiration time in seconds self.expiration = 60 * 60 * 24 * 365 * 5 # buy/sell actions will return order id by default self.returnOrderId = 'head' self.log = logging.LoggerAdapter(logging.getLogger('dexbot.orderengine'), {})
def new_func(ctx, *args, **kwargs): if not os.path.isfile(ctx.obj["configfile"]): Config(path=ctx.obj['configfile']) ctx.config = yaml.safe_load(open(ctx.obj["configfile"])) return ctx.invoke(f, *args, **kwargs)
def __init__(self, name, config=None, onAccount=None, onOrderMatched=None, onOrderPlaced=None, onMarketUpdate=None, onUpdateCallOrder=None, ontick=None, bitshares_instance=None, *args, **kwargs): # BitShares instance self.bitshares = bitshares_instance or shared_bitshares_instance() # Storage Storage.__init__(self, name) # Events Events.__init__(self) if ontick: self.ontick += ontick if onMarketUpdate: self.onMarketUpdate += onMarketUpdate if onAccount: self.onAccount += onAccount if onOrderMatched: self.onOrderMatched += onOrderMatched if onOrderPlaced: self.onOrderPlaced += onOrderPlaced if onUpdateCallOrder: self.onUpdateCallOrder += onUpdateCallOrder # Redirect this event to also call order placed and order matched self.onMarketUpdate += self._callbackPlaceFillOrders self.assets_intersections_data = None if config: self.config = config self.assets_intersections_data = Config.assets_intersections( config) else: self.config = config = Config.get_worker_config_file(name) # Get worker's parameters from the config self.worker = config["workers"][name] # Recheck flag - Tell the strategy to check for updated orders self.recheck_orders = False # Count of orders to be fetched from the API self.fetch_depth = 8 # What percent of balance the worker should use self.operational_percent_quote = self.worker.get( 'operational_percent_quote', 0) / 100 self.operational_percent_base = self.worker.get( 'operational_percent_base', 0) / 100 # Get Bitshares account and market for this worker self._account = Account(self.worker["account"], full=True, bitshares_instance=self.bitshares) self._market = Market(config["workers"][name]["market"], bitshares_instance=self.bitshares) # Set fee asset fee_asset_symbol = self.worker.get('fee_asset') if fee_asset_symbol: try: self.fee_asset = Asset(fee_asset_symbol, bitshares_instance=self.bitshares) except bitshares.exceptions.AssetDoesNotExistsException: self.fee_asset = Asset('1.3.0', bitshares_instance=self.bitshares) else: # If there is no fee asset, use BTS self.fee_asset = Asset('1.3.0', bitshares_instance=self.bitshares) # CER cache self.core_exchange_rate = None # Ticker self.ticker = self._market.ticker # Settings for bitshares instance self.bitshares.bundle = bool(self.worker.get("bundle", False)) # Disabled flag - this flag can be flipped to True by a worker and will be reset to False after reset only self.disabled = False # Order expiration time in seconds self.expiration = 60 * 60 * 24 * 365 * 5 # buy/sell actions will return order id by default self.returnOrderId = 'head' # A private logger that adds worker identify data to the LogRecord self.log = logging.LoggerAdapter( logging.getLogger('dexbot.per_worker'), { 'worker_name': name, 'account': self.worker['account'], 'market': self.worker['market'], 'is_disabled': lambda: self.disabled }) self.orders_log = logging.LoggerAdapter( logging.getLogger('dexbot.orders_log'), {})
def validate_account_not_in_use(cls, account): workers = Config().workers_data for worker_name, worker in workers.items(): if worker['account'] == account: return False return True