diff --git a/dexbot/__init__.py b/dexbot/__init__.py index 850505a32..e6d0c4f45 100644 --- a/dexbot/__init__.py +++ b/dexbot/__init__.py @@ -1 +1 @@ -__version__ = '0.1.10' +__version__ = '0.1.12' diff --git a/dexbot/controllers/create_worker_controller.py b/dexbot/controllers/create_worker_controller.py index 6e556a216..28ae5cbf7 100644 --- a/dexbot/controllers/create_worker_controller.py +++ b/dexbot/controllers/create_worker_controller.py @@ -124,17 +124,21 @@ def get_account(worker_data): return worker_data['account'] @staticmethod - def get_target_amount(worker_data): - return worker_data['target']['amount'] + def get_amount(worker_data): + return worker_data.get('amount', 0) @staticmethod - def get_target_center_price(worker_data): - return worker_data['target']['center_price'] + def get_amount_relative(worker_data): + return worker_data.get('amount_relative', False) @staticmethod - def get_target_center_price_dynamic(worker_data): - return worker_data['target']['center_price_dynamic'] + def get_center_price(worker_data): + return worker_data.get('center_price', 0) @staticmethod - def get_target_spread(worker_data): - return worker_data['target']['spread'] + def get_center_price_dynamic(worker_data): + return worker_data.get('center_price_dynamic', True) + + @staticmethod + def get_spread(worker_data): + return worker_data.get('spread', 5) diff --git a/dexbot/strategies/relative_orders.py b/dexbot/strategies/relative_orders.py index a595b3390..3320c4cd4 100644 --- a/dexbot/strategies/relative_orders.py +++ b/dexbot/strategies/relative_orders.py @@ -1,6 +1,5 @@ from dexbot.basestrategy import BaseStrategy from dexbot.queue.idle_queue import idle_add - from bitshares.amount import Amount @@ -19,16 +18,17 @@ def __init__(self, *args, **kwargs): self.error_onMarketUpdate = self.error self.error_onAccount = self.error - self.target = self.worker.get("target", {}) - self.is_center_price_dynamic = self.target["center_price_dynamic"] + self.is_center_price_dynamic = self.worker["center_price_dynamic"] if self.is_center_price_dynamic: self.center_price = None else: - self.center_price = self.target["center_price"] + self.center_price = self.worker["center_price"] + + self.is_relative_order_size = self.worker['amount_relative'] + self.order_size = float(self.worker['amount']) self.buy_price = None self.sell_price = None - self.calculate_order_prices() self.initial_balance = self['initial_balance'] or 0 self.worker_name = kwargs.get('name') @@ -36,12 +36,35 @@ def __init__(self, *args, **kwargs): self.check_orders() + @property + def amount_quote(self): + """"" + Get quote amount, calculate if order size is relative + """"" + if self.is_relative_order_size: + quote_balance = float(self.balance(self.market["quote"])) + return quote_balance * (self.order_size / 100) + else: + return self.order_size + + @property + def amount_base(self): + """"" + Get base amount, calculate if order size is relative + """"" + if self.is_relative_order_size: + base_balance = float(self.balance(self.market["base"])) + # amount = % of balance / buy_price = amount combined with calculated price to give % of balance + return base_balance * (self.order_size / 100) / self.buy_price + else: + return self.order_size + def calculate_order_prices(self): if self.is_center_price_dynamic: self.center_price = self.calculate_center_price - self.buy_price = self.center_price * (1 - (self.target["spread"] / 2) / 100) - self.sell_price = self.center_price * (1 + (self.target["spread"] / 2) / 100) + self.buy_price = self.center_price * (1 - (self.worker["spread"] / 2) / 100) + self.sell_price = self.center_price * (1 + (self.worker["spread"] / 2) / 100) def error(self, *args, **kwargs): self.cancel_all() @@ -50,7 +73,6 @@ def error(self, *args, **kwargs): def update_orders(self): self.log.info('Change detected, updating orders') - amount = self.target['amount'] # Recalculate buy and sell order prices self.calculate_order_prices() @@ -60,42 +82,46 @@ def update_orders(self): order_ids = [] + amount_base = self.amount_base + amount_quote = self.amount_quote + # Buy Side - if float(self.balance(self.market["base"])) < self.buy_price * amount: + if float(self.balance(self.market["base"])) < self.buy_price * amount_base: self.log.critical( - 'Insufficient buy balance, needed {} {}'.format(self.buy_price * amount, self.market['base']['symbol']) + 'Insufficient buy balance, needed {} {}'.format(self.buy_price * amount_base, + self.market['base']['symbol']) ) self.disabled = True else: buy_transaction = self.market.buy( self.buy_price, - Amount(amount=amount, asset=self.market["quote"]), + Amount(amount=amount_base, asset=self.market["quote"]), account=self.account, returnOrderId="head" ) buy_order = self.get_order(buy_transaction['orderid']) - self.log.info('Placed a buy order for {} {} @ {}'.format(amount, - self.market["quote"]['symbol'], + self.log.info('Placed a buy order for {} {} @ {}'.format(self.buy_price * amount_base, + self.market["base"]['symbol'], self.buy_price)) if buy_order: self['buy_order'] = buy_order order_ids.append(buy_transaction['orderid']) # Sell Side - if float(self.balance(self.market["quote"])) < amount: + if float(self.balance(self.market["quote"])) < amount_quote: self.log.critical( - "Insufficient sell balance, needed {} {}".format(amount, self.market['quote']['symbol']) + "Insufficient sell balance, needed {} {}".format(amount_quote, self.market['quote']['symbol']) ) self.disabled = True else: sell_transaction = self.market.sell( self.sell_price, - Amount(amount=amount, asset=self.market["quote"]), + Amount(amount=amount_quote, asset=self.market["quote"]), account=self.account, returnOrderId="head" ) sell_order = self.get_order(sell_transaction['orderid']) - self.log.info('Placed a sell order for {} {} @ {}'.format(amount, + self.log.info('Placed a sell order for {} {} @ {}'.format(amount_quote, self.market["quote"]['symbol'], self.sell_price)) if sell_order: diff --git a/dexbot/views/create_worker.py b/dexbot/views/create_worker.py index 4ac723965..bca589b0b 100644 --- a/dexbot/views/create_worker.py +++ b/dexbot/views/create_worker.py @@ -23,8 +23,23 @@ def __init__(self, controller): self.ui.save_button.clicked.connect(self.handle_save) self.ui.cancel_button.clicked.connect(self.reject) self.ui.center_price_dynamic_checkbox.stateChanged.connect(self.onchange_center_price_dynamic_checkbox) + self.ui.relative_order_size_checkbox.stateChanged.connect(self.onchange_relative_order_size_checkbox) self.worker_data = {} + def onchange_relative_order_size_checkbox(self): + checkbox = self.ui.relative_order_size_checkbox + if checkbox.isChecked(): + self.ui.amount_input.setSuffix('%') + self.ui.amount_input.setDecimals(2) + self.ui.amount_input.setMaximum(100.00) + self.ui.amount_input.setValue(10.00) + self.ui.amount_input.setMinimumWidth(151) + else: + self.ui.amount_input.setSuffix('') + self.ui.amount_input.setDecimals(8) + self.ui.amount_input.setMaximum(1000000000.000000) + self.ui.amount_input.setValue(0.000000) + def onchange_center_price_dynamic_checkbox(self): checkbox = self.ui.center_price_dynamic_checkbox if checkbox.isChecked(): @@ -96,12 +111,12 @@ def handle_save(self): ui = self.ui spread = float(ui.spread_input.text()[:-1]) # Remove the percentage character from the end - target = { - 'amount': float(ui.amount_input.text()), - 'center_price': float(ui.center_price_input.text()), - 'center_price_dynamic': bool(ui.center_price_dynamic_checkbox.isChecked()), - 'spread': spread - } + + # If order size is relative, remove percentage character in the end + if ui.relative_order_size_checkbox.isChecked(): + amount = float(ui.amount_input.text()[:-1]) + else: + amount = ui.amount_input.text() base_asset = ui.base_asset_input.currentText() quote_asset = ui.quote_asset_input.text() @@ -112,7 +127,11 @@ def handle_save(self): 'market': '{}/{}'.format(quote_asset, base_asset), 'module': worker_module, 'strategy': strategy, - 'target': target + 'amount': amount, + 'amount_relative': bool(ui.relative_order_size_checkbox.isChecked()), + 'center_price': float(ui.center_price_input.text()), + 'center_price_dynamic': bool(ui.center_price_dynamic_checkbox.isChecked()), + 'spread': spread } self.worker_name = ui.worker_name_input.text() self.accept() diff --git a/dexbot/views/edit_worker.py b/dexbot/views/edit_worker.py index 480c4c72b..533db183b 100644 --- a/dexbot/views/edit_worker.py +++ b/dexbot/views/edit_worker.py @@ -20,10 +20,19 @@ def __init__(self, controller, worker_name, config): self.base_asset_input.addItems(self.controller.base_assets) self.quote_asset_input.setText(self.controller.get_quote_asset(worker_data)) self.account_name.setText(self.controller.get_account(worker_data)) - self.amount_input.setValue(self.controller.get_target_amount(worker_data)) - self.center_price_input.setValue(self.controller.get_target_center_price(worker_data)) - center_price_dynamic = self.controller.get_target_center_price_dynamic(worker_data) + if self.controller.get_amount_relative(worker_data): + self.order_size_input_to_relative() + self.relative_order_size_checkbox.setChecked(True) + else: + self.order_size_input_to_static() + self.relative_order_size_checkbox.setChecked(False) + + self.amount_input.setValue(float(self.controller.get_amount(worker_data))) + + self.center_price_input.setValue(self.controller.get_center_price(worker_data)) + + center_price_dynamic = self.controller.get_center_price_dynamic(worker_data) if center_price_dynamic: self.center_price_input.setEnabled(False) self.center_price_dynamic_checkbox.setChecked(True) @@ -31,12 +40,36 @@ def __init__(self, controller, worker_name, config): self.center_price_input.setEnabled(True) self.center_price_dynamic_checkbox.setChecked(False) - self.spread_input.setValue(self.controller.get_target_spread(worker_data)) + self.spread_input.setValue(self.controller.get_spread(worker_data)) self.save_button.clicked.connect(self.handle_save) self.cancel_button.clicked.connect(self.reject) self.center_price_dynamic_checkbox.stateChanged.connect(self.onchange_center_price_dynamic_checkbox) + self.center_price_dynamic_checkbox.stateChanged.connect(self.onchange_center_price_dynamic_checkbox) + self.relative_order_size_checkbox.stateChanged.connect(self.onchange_relative_order_size_checkbox) self.worker_data = {} + def order_size_input_to_relative(self): + input_field = self.amount_input + input_field.setSuffix('%') + input_field.setDecimals(2) + input_field.setMaximum(100.00) + input_field.setMinimumWidth(151) + + def order_size_input_to_static(self): + input_field = self.amount_input + input_field.setSuffix('') + input_field.setDecimals(8) + input_field.setMaximum(1000000000.000000) + input_field.setMinimumWidth(151) + + def onchange_relative_order_size_checkbox(self): + if self.relative_order_size_checkbox.isChecked(): + self.order_size_input_to_relative() + self.amount_input.setValue(10.00) + else: + self.order_size_input_to_static() + self.amount_input.setValue(0.000000) + def onchange_center_price_dynamic_checkbox(self): checkbox = self.center_price_dynamic_checkbox if checkbox.isChecked(): @@ -96,12 +129,12 @@ def handle_save(self): return spread = float(self.spread_input.text()[:-1]) # Remove the percentage character from the end - target = { - 'amount': float(self.amount_input.text()), - 'center_price': float(self.center_price_input.text()), - 'center_price_dynamic': bool(self.center_price_dynamic_checkbox.isChecked()), - 'spread': spread - } + + # If order size is relative, remove percentage character in the end + if self.relative_order_size_checkbox.isChecked(): + amount = float(self.amount_input.text()[:-1]) + else: + amount = self.amount_input.text() base_asset = self.base_asset_input.currentText() quote_asset = self.quote_asset_input.text() @@ -112,7 +145,11 @@ def handle_save(self): 'market': '{}/{}'.format(quote_asset, base_asset), 'module': worker_module, 'strategy': strategy, - 'target': target + 'amount': amount, + 'amount_relative': bool(self.relative_order_size_checkbox.isChecked()), + 'center_price': float(self.center_price_input.text()), + 'center_price_dynamic': bool(self.center_price_dynamic_checkbox.isChecked()), + 'spread': spread } self.worker_name = self.worker_name_input.text() self.accept() diff --git a/dexbot/views/ui/create_worker_window.ui b/dexbot/views/ui/create_worker_window.ui index aba78c846..b19e4458d 100644 --- a/dexbot/views/ui/create_worker_window.ui +++ b/dexbot/views/ui/create_worker_window.ui @@ -7,7 +7,7 @@ 0 0 418 - 507 + 529 @@ -235,11 +235,11 @@ 8 - 999999999.998999953269958 + 1000000000.000000000000000 - + @@ -267,7 +267,7 @@ - + false @@ -304,7 +304,7 @@ - + @@ -332,7 +332,7 @@ - + @@ -360,7 +360,7 @@ - + Calculate center price dynamically @@ -370,6 +370,13 @@ + + + + Relative order size + + + diff --git a/dexbot/views/ui/edit_worker_window.ui b/dexbot/views/ui/edit_worker_window.ui index fd4b61ea6..354ce3da0 100644 --- a/dexbot/views/ui/edit_worker_window.ui +++ b/dexbot/views/ui/edit_worker_window.ui @@ -7,7 +7,7 @@ 0 0 400 - 459 + 486 @@ -252,11 +252,11 @@ 8 - 999999999.998999953269958 + 1000000000.000000000000000 - + @@ -284,7 +284,7 @@ - + false @@ -321,7 +321,14 @@ - + + + + Calculate center price dynamically + + + + @@ -349,7 +356,7 @@ - + @@ -377,10 +384,10 @@ - - + + - Calculate center price dynamically + Relative order size