aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIsmaël Bouya <ismael.bouya@normalesup.org>2018-04-02 19:20:48 +0200
committerIsmaël Bouya <ismael.bouya@normalesup.org>2018-04-02 19:20:48 +0200
commit3699463ad7774883070d52a77a0d495fdcce6bbc (patch)
treeb8216162ee14e27695e4b46cfb26825ccfdb7e25
parent013d60a77b223a87ffd1c19cd563227e10ca370d (diff)
parent7a676e2b0db5a168f08b419701cb71c28d7c76ee (diff)
downloadTrader-3699463ad7774883070d52a77a0d495fdcce6bbc.tar.gz
Trader-3699463ad7774883070d52a77a0d495fdcce6bbc.tar.zst
Trader-3699463ad7774883070d52a77a0d495fdcce6bbc.zip
Merge branch 'dev'v1.1
-rw-r--r--portfolio.py19
-rw-r--r--test.py118
2 files changed, 136 insertions, 1 deletions
diff --git a/portfolio.py b/portfolio.py
index 9dae23e..9e98c43 100644
--- a/portfolio.py
+++ b/portfolio.py
@@ -381,6 +381,14 @@ class Trade:
381 self.orders.append(order) 381 self.orders.append(order)
382 return order 382 return order
383 383
384 def reopen_same_order(self, order):
385 new_order = Order(order.action, order.amount, order.rate,
386 order.base_currency, order.trade_type, self.market,
387 self, close_if_possible=order.close_if_possible)
388 self.orders.append(new_order)
389 new_order.run()
390 return new_order
391
384 def as_json(self): 392 def as_json(self):
385 return { 393 return {
386 "action": self.action, 394 "action": self.action,
@@ -542,6 +550,15 @@ class Order:
542 self.fetch() 550 self.fetch()
543 return self.status 551 return self.status
544 552
553 def fix_disappeared_order(self):
554 if self.status.startswith("closed") and \
555 len(self.mouvements) == 1 and \
556 self.mouvements[0].total_in_base == 0:
557 self.status = "error_disappeared"
558 new_order = self.trade.reopen_same_order(self)
559 self.market.report.log_error("fetch",
560 message="Order {} disappeared, recreating it as {}".format(self, new_order))
561
545 def mark_finished_order(self): 562 def mark_finished_order(self):
546 if self.status.startswith("closed") and self.market.debug: 563 if self.status.startswith("closed") and self.market.debug:
547 self.market.report.log_debug_action("Mark {} as finished".format(self)) 564 self.market.report.log_debug_action("Mark {} as finished".format(self))
@@ -565,6 +582,8 @@ class Order:
565 582
566 self.fetch_mouvements() 583 self.fetch_mouvements()
567 584
585 self.fix_disappeared_order()
586
568 self.mark_finished_order() 587 self.mark_finished_order()
569 # FIXME: consider open order with dust remaining as closed 588 # FIXME: consider open order with dust remaining as closed
570 589
diff --git a/test.py b/test.py
index 9ea9df4..7b17f9e 100644
--- a/test.py
+++ b/test.py
@@ -2406,6 +2406,27 @@ class TradeTest(WebMockTestCase):
2406 order1.filled_amount.assert_called_with(in_base_currency=True) 2406 order1.filled_amount.assert_called_with(in_base_currency=True)
2407 order2.filled_amount.assert_called_with(in_base_currency=True) 2407 order2.filled_amount.assert_called_with(in_base_currency=True)
2408 2408
2409 def test_reopen_same_order(self):
2410 value_from = portfolio.Amount("BTC", "0.5")
2411 value_from.linked_to = portfolio.Amount("ETH", "10.0")
2412 value_to = portfolio.Amount("BTC", "1.0")
2413 trade = portfolio.Trade(value_from, value_to, "ETH", self.m)
2414 order = portfolio.Order("buy", portfolio.Amount("ETH", 10),
2415 D("0.1"), "BTC", "long", self.m, "trade")
2416 with mock.patch("portfolio.Order.run") as run:
2417 new_order = trade.reopen_same_order(order)
2418 self.assertEqual("buy", new_order.action)
2419 self.assertEqual(portfolio.Amount("ETH", 10), new_order.amount)
2420 self.assertEqual(D("0.1"), new_order.rate)
2421 self.assertEqual("BTC", new_order.base_currency)
2422 self.assertEqual("long", new_order.trade_type)
2423 self.assertEqual(self.m, new_order.market)
2424 self.assertEqual(False, new_order.close_if_possible)
2425 self.assertEqual(trade, new_order.trade)
2426 run.assert_called_once()
2427 self.assertEqual(1, len(trade.orders))
2428 self.assertEqual(new_order, trade.orders[0])
2429
2409 @mock.patch.object(portfolio.Computation, "compute_value") 2430 @mock.patch.object(portfolio.Computation, "compute_value")
2410 @mock.patch.object(portfolio.Trade, "filled_amount") 2431 @mock.patch.object(portfolio.Trade, "filled_amount")
2411 @mock.patch.object(portfolio, "Order") 2432 @mock.patch.object(portfolio, "Order")
@@ -3038,8 +3059,9 @@ class OrderTest(WebMockTestCase):
3038 self.m.report.log_debug_action.assert_called_once() 3059 self.m.report.log_debug_action.assert_called_once()
3039 3060
3040 @mock.patch.object(portfolio.Order, "fetch_mouvements") 3061 @mock.patch.object(portfolio.Order, "fetch_mouvements")
3062 @mock.patch.object(portfolio.Order, "fix_disappeared_order")
3041 @mock.patch.object(portfolio.Order, "mark_finished_order") 3063 @mock.patch.object(portfolio.Order, "mark_finished_order")
3042 def test_fetch(self, mark_finished_order, fetch_mouvements): 3064 def test_fetch(self, mark_finished_order, fix_disappeared_order, fetch_mouvements):
3043 order = portfolio.Order("buy", portfolio.Amount("ETH", 10), 3065 order = portfolio.Order("buy", portfolio.Amount("ETH", 10),
3044 D("0.1"), "BTC", "long", self.m, "trade") 3066 D("0.1"), "BTC", "long", self.m, "trade")
3045 order.id = 45 3067 order.id = 45
@@ -3050,6 +3072,7 @@ class OrderTest(WebMockTestCase):
3050 self.m.report.log_debug_action.reset_mock() 3072 self.m.report.log_debug_action.reset_mock()
3051 self.m.ccxt.fetch_order.assert_not_called() 3073 self.m.ccxt.fetch_order.assert_not_called()
3052 mark_finished_order.assert_not_called() 3074 mark_finished_order.assert_not_called()
3075 fix_disappeared_order.assert_not_called()
3053 fetch_mouvements.assert_not_called() 3076 fetch_mouvements.assert_not_called()
3054 3077
3055 with self.subTest(debug=False): 3078 with self.subTest(debug=False):
@@ -3067,6 +3090,7 @@ class OrderTest(WebMockTestCase):
3067 self.assertEqual(1, len(order.results)) 3090 self.assertEqual(1, len(order.results))
3068 self.m.report.log_debug_action.assert_not_called() 3091 self.m.report.log_debug_action.assert_not_called()
3069 mark_finished_order.assert_called_once() 3092 mark_finished_order.assert_called_once()
3093 fix_disappeared_order.assert_called_once()
3070 3094
3071 mark_finished_order.reset_mock() 3095 mark_finished_order.reset_mock()
3072 with self.subTest(missing_order=True): 3096 with self.subTest(missing_order=True):
@@ -3077,6 +3101,98 @@ class OrderTest(WebMockTestCase):
3077 self.assertEqual("closed_unknown", order.status) 3101 self.assertEqual("closed_unknown", order.status)
3078 mark_finished_order.assert_called_once() 3102 mark_finished_order.assert_called_once()
3079 3103
3104 def test_fix_disappeared_order(self):
3105 with self.subTest("Open order"):
3106 order = portfolio.Order("buy", portfolio.Amount("ETH", 10),
3107 D("0.1"), "BTC", "long", self.m, "trade")
3108 order.id = 45
3109 order.mouvements.append(portfolio.Mouvement("XRP", "BTC", {
3110 "tradeID":21336541,
3111 "currencyPair":"BTC_XRP",
3112 "type":"sell",
3113 "rate":"0.00007013",
3114 "amount":"0.00000222",
3115 "total":"0.00000000",
3116 "fee":"0.00150000",
3117 "date":"2018-04-02 00:09:13"
3118 }))
3119 with mock.patch.object(order, "trade") as trade:
3120 order.fix_disappeared_order()
3121 trade.reopen_same_order.assert_not_called()
3122
3123 with self.subTest("Non-zero amount"):
3124 order = portfolio.Order("buy", portfolio.Amount("ETH", 10),
3125 D("0.1"), "BTC", "long", self.m, "trade")
3126 order.id = 45
3127 order.status = "closed"
3128 order.mouvements.append(portfolio.Mouvement("XRP", "BTC", {
3129 "tradeID":21336541,
3130 "currencyPair":"BTC_XRP",
3131 "type":"sell",
3132 "rate":"0.00007013",
3133 "amount":"0.00000222",
3134 "total":"0.00000010",
3135 "fee":"0.00150000",
3136 "date":"2018-04-02 00:09:13"
3137 }))
3138 with mock.patch.object(order, "trade") as trade:
3139 order.fix_disappeared_order()
3140 self.assertEqual("closed", order.status)
3141 trade.reopen_same_order.assert_not_called()
3142
3143 with self.subTest("Other mouvements"):
3144 order = portfolio.Order("buy", portfolio.Amount("ETH", 10),
3145 D("0.1"), "BTC", "long", self.m, "trade")
3146 order.id = 45
3147 order.status = "closed"
3148 order.mouvements.append(portfolio.Mouvement("XRP", "BTC", {
3149 "tradeID":21336541,
3150 "currencyPair":"BTC_XRP",
3151 "type":"sell",
3152 "rate":"0.00007013",
3153 "amount":"0.00000222",
3154 "total":"0.00000001",
3155 "fee":"0.00150000",
3156 "date":"2018-04-02 00:09:13"
3157 }))
3158 order.mouvements.append(portfolio.Mouvement("XRP", "BTC", {
3159 "tradeID":21336541,
3160 "currencyPair":"BTC_XRP",
3161 "type":"sell",
3162 "rate":"0.00007013",
3163 "amount":"0.00000222",
3164 "total":"0.00000000",
3165 "fee":"0.00150000",
3166 "date":"2018-04-02 00:09:13"
3167 }))
3168 with mock.patch.object(order, "trade") as trade:
3169 order.fix_disappeared_order()
3170 self.assertEqual("closed", order.status)
3171 trade.reopen_same_order.assert_not_called()
3172
3173 with self.subTest("Order disappeared"):
3174 order = portfolio.Order("buy", portfolio.Amount("ETH", 10),
3175 D("0.1"), "BTC", "long", self.m, "trade")
3176 order.id = 45
3177 order.status = "closed"
3178 order.mouvements.append(portfolio.Mouvement("XRP", "BTC", {
3179 "tradeID":21336541,
3180 "currencyPair":"BTC_XRP",
3181 "type":"sell",
3182 "rate":"0.00007013",
3183 "amount":"0.00000222",
3184 "total":"0.00000000",
3185 "fee":"0.00150000",
3186 "date":"2018-04-02 00:09:13"
3187 }))
3188 with mock.patch.object(order, "trade") as trade:
3189 trade.reopen_same_order.return_value = "New order"
3190 order.fix_disappeared_order()
3191 self.assertEqual("error_disappeared", order.status)
3192 trade.reopen_same_order.assert_called_once_with(order)
3193 self.m.report.log_error.assert_called_once_with('fetch',
3194 message='Order Order(buy long 10.00000000 ETH at 0.1 BTC [error_disappeared]) disappeared, recreating it as New order')
3195
3080 @mock.patch.object(portfolio.Order, "fetch") 3196 @mock.patch.object(portfolio.Order, "fetch")
3081 def test_get_status(self, fetch): 3197 def test_get_status(self, fetch):
3082 with self.subTest(debug=True): 3198 with self.subTest(debug=True):