diff options
author | Ismaël Bouya <ismael.bouya@normalesup.org> | 2018-02-11 22:40:30 +0100 |
---|---|---|
committer | Ismaël Bouya <ismael.bouya@normalesup.org> | 2018-02-11 22:40:30 +0100 |
commit | 5a72ded790f8b5e7c9b38a3cc91c12fbfb6cb97a (patch) | |
tree | e12aa9ec9a5c543442aa512ee0d485ccf9f02906 /portfolio.py | |
parent | 1aa7d4fa2ec3c2b3268bef31a666ca6e1aaa6563 (diff) | |
download | Trader-5a72ded790f8b5e7c9b38a3cc91c12fbfb6cb97a.tar.gz Trader-5a72ded790f8b5e7c9b38a3cc91c12fbfb6cb97a.tar.zst Trader-5a72ded790f8b5e7c9b38a3cc91c12fbfb6cb97a.zip |
Add missing tests
Diffstat (limited to 'portfolio.py')
-rw-r--r-- | portfolio.py | 55 |
1 files changed, 28 insertions, 27 deletions
diff --git a/portfolio.py b/portfolio.py index b629966..e98689e 100644 --- a/portfolio.py +++ b/portfolio.py | |||
@@ -1,4 +1,5 @@ | |||
1 | import time | 1 | import time |
2 | from datetime import datetime | ||
2 | from decimal import Decimal as D, ROUND_DOWN | 3 | from decimal import Decimal as D, ROUND_DOWN |
3 | # Put your poloniex api key in market.py | 4 | # Put your poloniex api key in market.py |
4 | from json import JSONDecodeError | 5 | from json import JSONDecodeError |
@@ -272,7 +273,7 @@ class Trade: | |||
272 | if self.base_currency == self.currency: | 273 | if self.base_currency == self.currency: |
273 | return None | 274 | return None |
274 | 275 | ||
275 | if self.value_from < self.value_to: | 276 | if abs(self.value_from) < abs(self.value_to): |
276 | return "acquire" | 277 | return "acquire" |
277 | else: | 278 | else: |
278 | return "dispose" | 279 | return "dispose" |
@@ -301,19 +302,16 @@ class Trade: | |||
301 | if tick in [0, 1, 3, 4, 6]: | 302 | if tick in [0, 1, 3, 4, 6]: |
302 | print("{}, tick {}, waiting".format(order, tick)) | 303 | print("{}, tick {}, waiting".format(order, tick)) |
303 | elif tick == 2: | 304 | elif tick == 2: |
304 | self.prepare_order(compute_value=lambda x, y: (x[y] + x["average"]) / 2) | 305 | new_order = self.prepare_order(compute_value=lambda x, y: (x[y] + x["average"]) / 2) |
305 | new_order = self.orders[-1] | ||
306 | print("{}, tick {}, cancelling and adjusting to {}".format(order, tick, new_order)) | 306 | print("{}, tick {}, cancelling and adjusting to {}".format(order, tick, new_order)) |
307 | elif tick ==5: | 307 | elif tick ==5: |
308 | self.prepare_order(compute_value=lambda x, y: (x[y]*2 + x["average"]) / 3) | 308 | new_order = self.prepare_order(compute_value=lambda x, y: (x[y]*2 + x["average"]) / 3) |
309 | new_order = self.orders[-1] | ||
310 | print("{}, tick {}, cancelling and adjusting to {}".format(order, tick, new_order)) | 309 | print("{}, tick {}, cancelling and adjusting to {}".format(order, tick, new_order)) |
311 | elif tick >= 7: | 310 | elif tick >= 7: |
312 | if tick == 7: | 311 | if tick == 7: |
313 | print("{}, tick {}, fallbacking to market value".format(order, tick)) | 312 | print("{}, tick {}, fallbacking to market value".format(order, tick)) |
314 | if (tick - 7) % 3 == 0: | 313 | if (tick - 7) % 3 == 0: |
315 | self.prepare_order(compute_value="default") | 314 | new_order = self.prepare_order(compute_value="default") |
316 | new_order = self.orders[-1] | ||
317 | print("{}, tick {}, market value, cancelling and adjusting to {}".format(order, tick, new_order)) | 315 | print("{}, tick {}, market value, cancelling and adjusting to {}".format(order, tick, new_order)) |
318 | 316 | ||
319 | if new_order is not None: | 317 | if new_order is not None: |
@@ -322,7 +320,7 @@ class Trade: | |||
322 | 320 | ||
323 | def prepare_order(self, compute_value="default"): | 321 | def prepare_order(self, compute_value="default"): |
324 | if self.action is None: | 322 | if self.action is None: |
325 | return | 323 | return None |
326 | ticker = h.get_ticker(self.currency, self.base_currency, self.market) | 324 | ticker = h.get_ticker(self.currency, self.base_currency, self.market) |
327 | inverted = ticker["inverted"] | 325 | inverted = ticker["inverted"] |
328 | if inverted: | 326 | if inverted: |
@@ -387,11 +385,13 @@ class Trade: | |||
387 | 385 | ||
388 | if delta <= 0: | 386 | if delta <= 0: |
389 | print("Less to do than already filled: {}".format(delta)) | 387 | print("Less to do than already filled: {}".format(delta)) |
390 | return | 388 | return None |
391 | 389 | ||
392 | self.orders.append(Order(self.order_action(inverted), | 390 | order = Order(self.order_action(inverted), |
393 | delta, rate, base_currency, self.trade_type, | 391 | delta, rate, base_currency, self.trade_type, |
394 | self.market, self, close_if_possible=close_if_possible)) | 392 | self.market, self, close_if_possible=close_if_possible) |
393 | self.orders.append(order) | ||
394 | return order | ||
395 | 395 | ||
396 | def __repr__(self): | 396 | def __repr__(self): |
397 | return "Trade({} -> {} in {}, {})".format( | 397 | return "Trade({} -> {} in {}, {})".format( |
@@ -419,6 +419,8 @@ class Order: | |||
419 | self.status = "pending" | 419 | self.status = "pending" |
420 | self.trade = trade | 420 | self.trade = trade |
421 | self.close_if_possible = close_if_possible | 421 | self.close_if_possible = close_if_possible |
422 | self.id = None | ||
423 | self.fetch_cache_timestamp = None | ||
422 | 424 | ||
423 | def __repr__(self): | 425 | def __repr__(self): |
424 | return "Order({} {} {} at {} {} [{}]{})".format( | 426 | return "Order({} {} {} at {} {} [{}]{})".format( |
@@ -439,6 +441,10 @@ class Order: | |||
439 | return "margin" | 441 | return "margin" |
440 | 442 | ||
441 | @property | 443 | @property |
444 | def open(self): | ||
445 | return self.status == "open" | ||
446 | |||
447 | @property | ||
442 | def pending(self): | 448 | def pending(self): |
443 | return self.status == "pending" | 449 | return self.status == "pending" |
444 | 450 | ||
@@ -446,10 +452,6 @@ class Order: | |||
446 | def finished(self): | 452 | def finished(self): |
447 | return self.status == "closed" or self.status == "canceled" or self.status == "error" | 453 | return self.status == "closed" or self.status == "canceled" or self.status == "error" |
448 | 454 | ||
449 | @property | ||
450 | def id(self): | ||
451 | return self.results[0]["id"] | ||
452 | |||
453 | def run(self): | 455 | def run(self): |
454 | symbol = "{}/{}".format(self.amount.currency, self.base_currency) | 456 | symbol = "{}/{}".format(self.amount.currency, self.base_currency) |
455 | amount = round(self.amount, self.market.order_precision(symbol)).value | 457 | amount = round(self.amount, self.market.order_precision(symbol)).value |
@@ -457,26 +459,27 @@ class Order: | |||
457 | if TradeStore.debug: | 459 | if TradeStore.debug: |
458 | print("market.create_order('{}', 'limit', '{}', {}, price={}, account={})".format( | 460 | print("market.create_order('{}', 'limit', '{}', {}, price={}, account={})".format( |
459 | symbol, self.action, amount, self.rate, self.account)) | 461 | symbol, self.action, amount, self.rate, self.account)) |
460 | self.status = "open" | ||
461 | self.results.append({"debug": True, "id": -1}) | 462 | self.results.append({"debug": True, "id": -1}) |
462 | else: | 463 | else: |
463 | try: | 464 | try: |
464 | self.results.append(self.market.create_order(symbol, 'limit', self.action, amount, price=self.rate, account=self.account)) | 465 | self.results.append(self.market.create_order(symbol, 'limit', self.action, amount, price=self.rate, account=self.account)) |
465 | self.status = "open" | ||
466 | except Exception as e: | 466 | except Exception as e: |
467 | self.status = "error" | 467 | self.status = "error" |
468 | print("error when running market.create_order('{}', 'limit', '{}', {}, price={}, account={})".format( | 468 | print("error when running market.create_order('{}', 'limit', '{}', {}, price={}, account={})".format( |
469 | symbol, self.action, amount, self.rate, self.account)) | 469 | symbol, self.action, amount, self.rate, self.account)) |
470 | self.error_message = str("{}: {}".format(e.__class__.__name__, e)) | 470 | self.error_message = str("{}: {}".format(e.__class__.__name__, e)) |
471 | print(self.error_message) | 471 | print(self.error_message) |
472 | return | ||
473 | self.id = self.results[0]["id"] | ||
474 | self.status = "open" | ||
472 | 475 | ||
473 | def get_status(self): | 476 | def get_status(self): |
474 | if TradeStore.debug: | 477 | if TradeStore.debug: |
475 | return self.status | 478 | return self.status |
476 | # other states are "closed" and "canceled" | 479 | # other states are "closed" and "canceled" |
477 | if self.status == "open": | 480 | if not self.finished: |
478 | self.fetch() | 481 | self.fetch() |
479 | if self.status != "open": | 482 | if self.finished: |
480 | self.mark_finished_order() | 483 | self.mark_finished_order() |
481 | return self.status | 484 | return self.status |
482 | 485 | ||
@@ -487,15 +490,15 @@ class Order: | |||
487 | if self.trade_type == "short" and self.action == "buy" and self.close_if_possible: | 490 | if self.trade_type == "short" and self.action == "buy" and self.close_if_possible: |
488 | self.market.close_margin_position(self.amount.currency, self.base_currency) | 491 | self.market.close_margin_position(self.amount.currency, self.base_currency) |
489 | 492 | ||
490 | fetch_cache_timestamp = None | ||
491 | def fetch(self, force=False): | 493 | def fetch(self, force=False): |
492 | if TradeStore.debug or (not force and self.fetch_cache_timestamp is not None | 494 | if TradeStore.debug or (not force and self.fetch_cache_timestamp is not None |
493 | and time.time() - self.fetch_cache_timestamp < 10): | 495 | and time.time() - self.fetch_cache_timestamp < 10): |
494 | return | 496 | return |
495 | self.fetch_cache_timestamp = time.time() | 497 | self.fetch_cache_timestamp = time.time() |
496 | 498 | ||
497 | self.results.append(self.market.fetch_order(self.id)) | 499 | result = self.market.fetch_order(self.id) |
498 | result = self.results[-1] | 500 | self.results.append(result) |
501 | |||
499 | self.status = result["status"] | 502 | self.status = result["status"] |
500 | # Time at which the order started | 503 | # Time at which the order started |
501 | self.timestamp = result["datetime"] | 504 | self.timestamp = result["datetime"] |
@@ -503,11 +506,9 @@ class Order: | |||
503 | 506 | ||
504 | # FIXME: consider open order with dust remaining as closed | 507 | # FIXME: consider open order with dust remaining as closed |
505 | 508 | ||
506 | @property | ||
507 | def dust_amount_remaining(self): | 509 | def dust_amount_remaining(self): |
508 | return self.remaining_amount < 0.001 | 510 | return self.remaining_amount() < Amount(self.amount.currency, D("0.001")) |
509 | 511 | ||
510 | @property | ||
511 | def remaining_amount(self): | 512 | def remaining_amount(self): |
512 | if self.status == "open": | 513 | if self.status == "open": |
513 | self.fetch() | 514 | self.fetch() |
@@ -536,7 +537,7 @@ class Order: | |||
536 | if TradeStore.debug: | 537 | if TradeStore.debug: |
537 | self.status = "canceled" | 538 | self.status = "canceled" |
538 | return | 539 | return |
539 | self.market.cancel_order(self.result['id']) | 540 | self.market.cancel_order(self.id) |
540 | self.fetch() | 541 | self.fetch() |
541 | 542 | ||
542 | class Mouvement: | 543 | class Mouvement: |
@@ -552,6 +553,6 @@ class Mouvement: | |||
552 | # rate * total = total_in_base | 553 | # rate * total = total_in_base |
553 | self.total_in_base = Amount(base_currency, hash_["total"]) | 554 | self.total_in_base = Amount(base_currency, hash_["total"]) |
554 | 555 | ||
555 | if __name__ == '__main__': | 556 | if __name__ == '__main__': # pragma: no cover |
556 | from market import market | 557 | from market import market |
557 | h.print_orders(market) | 558 | h.print_orders(market) |