Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement different triggers to reset orders #273

Merged
merged 15 commits into from
Aug 29, 2018

Conversation

bitphage
Copy link
Collaborator

  • Always reset orders whether it was a filled, expired or manually
    cancelled order detected

  • Reset on partial fill (with % threshold, optional)

  • Allow to define custom order expiration time

  • Reset orders on market trade (optional)

  • Reset orders on center price change threshold (optional)

  • Also disable log message about correct orders to remove log noise

  • Writing of a trade log entry is disabled because we cannot properly
    distinguish an expired order from a filled one

Closes: #226, #270

- Always reset orders whether it was a filled, expired or manually
cancelled order detected
- Reset on partial fill (with % threshold, optional)
- Allow to define custom order expiration time
- Reset orders on market trade (optional)
- Reset orders on center price change threshold (optional)

- Also disable log message about correct orders to remove log noise
- Writing of a trade log entry is disabled because we cannot properly
distinguish an expired order from a filled one

Closes: Codaone#226, Codaone#270
if need_update:
self.update_orders()
else:
pass
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The point of logging "Orders correct on market" is that it's used as a status for the worker in the GUI.
In a case where the strategy is initialized but no action is required to be done after it, a status message "Initializing Relative Orders" will get stuck on the GUI and that will just confuse the user.

I implemented a fix for this here 347eedf#diff-472e57ad5bbb88571e326e56670648b7R173 but I think it's going to take a while until I can merge that to master, so could just copy the change from there?

@@ -108,7 +157,7 @@ def calculate_order_prices(self):
self.sell_price = self.center_price * math.sqrt(1 + self.spread)

def update_orders(self):
self.log.info('Change detected, updating orders')
#self.log.debug('Change detected, updating orders')
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't leave unneeded comments lying around. Changing this to debug is fine.

self.write_order_log(self.worker_name, order)
need_update = True
self.log.debug('Could not found order on the market, it was filled, expired or cancelled')
# FIXME: writing a log entry is disabled because we cannot distinguish an expired order
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would be better to disable order expiration setting for now, so that order logging isn't totally broken

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could also inform users that trades.csv will be useless if they use order expiration. Order expiration is a useful tool otherwise.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If that's fine then it only needs an if statement to check if order expiration setting is on

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suits me


# Check for conflicting settings
if self.is_reset_on_price_change and not self.is_center_price_dynamic:
self.log.error('reset_on_price_change requires Dynamic Center Price')
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use the human readable format for the names

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mikakoi do you mean human readable format inside the log message?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, Just change the message to 'Reset orders on center price change' requires 'Dynamic center price' or something

if self.is_reset_on_price_change and not self.is_center_price_dynamic:
self.log.error('reset_on_price_change requires Dynamic Center Price')
self.disabled = True
self.update_orders()
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason you changed check_orders() to update_orders()?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, because relative orders strategy is supposed to remove orders on exit, we can assume on initializing that we don't have any orders anyway, so there is no sense in checking something that should not be exist.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well you can actually keep the orders on the market with relative orders on exit. If you simply quit the program when relative orders is running, it leaves the orders on the market.

I just feel it's a waste to cancel those orders on start up.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I agree. Furthermore, we can add an option into GUI like "Keep orders on exit" to let the user decide should the bot keep orders or not.

As described by @mikakoi:
The point of logging "Orders correct on market" is that it's used as a
status for the worker in the GUI.
In a case where the strategy is initialized but no action is required to
be done after it, a status message "Initializing Relative Orders" will
get stuck on the GUI and that will just confuse the user.

Code part is from 347eedf

Closes: Codaone#270
There are maybe old orders from previous run, so give a chance to them.
We still need to cancel old orders on startup when "Reset orders on
center price change" is active. We don't know what the center price was
before.
@bitphage
Copy link
Collaborator Author

OK, updated the PR with proposed fixes.

delta = datetime.now() - self.last_check

# Only allow to check orders whether minimal time passed
if delta < timedelta(seconds=self.min_check_interval):
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This check doesn't work on initialization as self.last_check is set in the constructor

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is fine, we don't need it on initialization, this check is for rate-limiting only.

self.log.info("Orders correct on market")
if need_update:
self.update_orders()
elif self.initializing:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually you could just check for event == 'init', since you're passing that in the constructor.

Copy link
Collaborator Author

@bitphage bitphage Aug 28, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will not work because 'init' event is passed during initialization only, and thus code under if need_update will be used in 99% times. On the next check an event will be a real market event, not 'init'.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, the point of the log message is to display it only during initialization, it doesn't matter if it doesn't get ran after that

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

During initialization there will be another message "Done placing orders" whether everything fine.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well not really, if in the initialization phase the worker doesn't need to place any orders so it doesn't print the message. But it's fine since already removed the event parameter

Copy link
Collaborator Author

@bitphage bitphage Aug 29, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So no further changes required?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, merged the changes already

# be correct

if (self.is_reset_on_market_trade and
isinstance(event, FilledOrder)):
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should only be evaluated true if dynamic center price is on

ConfigElement('reset_on_partial_fill', 'bool', True, 'Reset orders on partial fill',
'Reset orders when buy or sell order is partially filled', None),
ConfigElement('partial_fill_threshold', 'float', 30, 'Fill threshold',
'Fill threshold to reset orders', (0, 100, 2, '%')),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe this should say Order fill threshold to reset orders to be more descriptive

@@ -1,8 +1,11 @@
import math
from datetime import datetime
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use from datetime import datetime, timedelta

This is option is actually not needed because it's duplicating behavior
of "Reset on center price change" with "threshold = 0"
check_orders() are called from __init__(), so it will not work because
initial "self.last_check = now"
@mikakoi mikakoi merged commit 901e880 into Codaone:master Aug 29, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants