Skip to content

Commit

Permalink
Merge pull request #69 from Codaone/relative-order-size-new
Browse files Browse the repository at this point in the history
Relative order size new
  • Loading branch information
mikakoi committed Apr 12, 2018
2 parents 417bb2a + 6fbd7c2 commit 8579c0e
Show file tree
Hide file tree
Showing 7 changed files with 160 additions and 60 deletions.
2 changes: 1 addition & 1 deletion dexbot/__init__.py
@@ -1 +1 @@
__version__ = '0.1.10'
__version__ = '0.1.12'
20 changes: 12 additions & 8 deletions dexbot/controllers/create_worker_controller.py
Expand Up @@ -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)
60 changes: 43 additions & 17 deletions 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


Expand All @@ -19,29 +18,53 @@ 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')
self.view = kwargs.get('view')

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()
Expand 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()
Expand All @@ -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:
Expand Down
33 changes: 26 additions & 7 deletions dexbot/views/create_worker.py
Expand Up @@ -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():
Expand Down Expand Up @@ -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()
Expand All @@ -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()
59 changes: 48 additions & 11 deletions dexbot/views/edit_worker.py
Expand Up @@ -20,23 +20,56 @@ 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)
else:
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():
Expand Down Expand Up @@ -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()
Expand All @@ -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()
21 changes: 14 additions & 7 deletions dexbot/views/ui/create_worker_window.ui
Expand Up @@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>418</width>
<height>507</height>
<height>529</height>
</rect>
</property>
<property name="windowTitle">
Expand Down Expand Up @@ -235,11 +235,11 @@
<number>8</number>
</property>
<property name="maximum">
<double>999999999.998999953269958</double>
<double>1000000000.000000000000000</double>
</property>
</widget>
</item>
<item row="1" column="0">
<item row="2" column="0">
<widget class="QLabel" name="center_price_label">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
Expand Down Expand Up @@ -267,7 +267,7 @@
</property>
</widget>
</item>
<item row="1" column="1">
<item row="2" column="1">
<widget class="QDoubleSpinBox" name="center_price_input">
<property name="enabled">
<bool>false</bool>
Expand Down Expand Up @@ -304,7 +304,7 @@
</property>
</widget>
</item>
<item row="3" column="0">
<item row="4" column="0">
<widget class="QLabel" name="spread_label">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
Expand Down Expand Up @@ -332,7 +332,7 @@
</property>
</widget>
</item>
<item row="3" column="1">
<item row="4" column="1">
<widget class="QDoubleSpinBox" name="spread_input">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
Expand Down Expand Up @@ -360,7 +360,7 @@
</property>
</widget>
</item>
<item row="2" column="1">
<item row="3" column="1">
<widget class="QCheckBox" name="center_price_dynamic_checkbox">
<property name="text">
<string>Calculate center price dynamically</string>
Expand All @@ -370,6 +370,13 @@
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QCheckBox" name="relative_order_size_checkbox">
<property name="text">
<string>Relative order size</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
Expand Down

0 comments on commit 8579c0e

Please sign in to comment.