diff options
Diffstat (limited to 'test.py')
-rw-r--r-- | test.py | 634 |
1 files changed, 634 insertions, 0 deletions
@@ -1444,6 +1444,139 @@ class MarketTest(WebMockTestCase): | |||
1444 | self.ccxt.transfer_balance.assert_any_call("USDT", 100, "exchange", "margin") | 1444 | self.ccxt.transfer_balance.assert_any_call("USDT", 100, "exchange", "margin") |
1445 | self.ccxt.transfer_balance.assert_any_call("ETC", 5, "margin", "exchange") | 1445 | self.ccxt.transfer_balance.assert_any_call("ETC", 5, "margin", "exchange") |
1446 | 1446 | ||
1447 | m.report.reset_mock() | ||
1448 | fetch_balances.reset_mock() | ||
1449 | with self.subTest(retry=True): | ||
1450 | with mock.patch("market.ReportStore"): | ||
1451 | m = market.Market(self.ccxt, self.market_args()) | ||
1452 | |||
1453 | value_from = portfolio.Amount("BTC", "0.0") | ||
1454 | value_from.linked_to = portfolio.Amount("ETH", "0.0") | ||
1455 | value_to = portfolio.Amount("BTC", "-3.0") | ||
1456 | trade = portfolio.Trade(value_from, value_to, "ETH", m) | ||
1457 | |||
1458 | m.trades.all = [trade] | ||
1459 | balance = portfolio.Balance("BTC", { "margin_in_position": "0", "margin_available": "0" }) | ||
1460 | m.balances.all = {"BTC": balance} | ||
1461 | |||
1462 | m.ccxt.transfer_balance.side_effect = [ | ||
1463 | market.ccxt.RequestTimeout, | ||
1464 | True | ||
1465 | ] | ||
1466 | m.move_balances() | ||
1467 | self.ccxt.transfer_balance.assert_has_calls([ | ||
1468 | mock.call("BTC", 3, "exchange", "margin"), | ||
1469 | mock.call("BTC", 3, "exchange", "margin") | ||
1470 | ]) | ||
1471 | self.assertEqual(2, fetch_balances.call_count) | ||
1472 | m.report.log_error.assert_called_with(mock.ANY, message="Retrying", exception=mock.ANY) | ||
1473 | self.assertEqual(2, m.report.log_move_balances.call_count) | ||
1474 | |||
1475 | self.ccxt.transfer_balance.reset_mock() | ||
1476 | m.report.reset_mock() | ||
1477 | fetch_balances.reset_mock() | ||
1478 | with self.subTest(retry=True, too_much=True): | ||
1479 | with mock.patch("market.ReportStore"): | ||
1480 | m = market.Market(self.ccxt, self.market_args()) | ||
1481 | |||
1482 | value_from = portfolio.Amount("BTC", "0.0") | ||
1483 | value_from.linked_to = portfolio.Amount("ETH", "0.0") | ||
1484 | value_to = portfolio.Amount("BTC", "-3.0") | ||
1485 | trade = portfolio.Trade(value_from, value_to, "ETH", m) | ||
1486 | |||
1487 | m.trades.all = [trade] | ||
1488 | balance = portfolio.Balance("BTC", { "margin_in_position": "0", "margin_available": "0" }) | ||
1489 | m.balances.all = {"BTC": balance} | ||
1490 | |||
1491 | m.ccxt.transfer_balance.side_effect = [ | ||
1492 | market.ccxt.RequestTimeout, | ||
1493 | market.ccxt.RequestTimeout, | ||
1494 | market.ccxt.RequestTimeout, | ||
1495 | market.ccxt.RequestTimeout, | ||
1496 | market.ccxt.RequestTimeout, | ||
1497 | ] | ||
1498 | with self.assertRaises(market.ccxt.RequestTimeout): | ||
1499 | m.move_balances() | ||
1500 | |||
1501 | self.ccxt.transfer_balance.reset_mock() | ||
1502 | m.report.reset_mock() | ||
1503 | fetch_balances.reset_mock() | ||
1504 | with self.subTest(retry=True, partial_result=True): | ||
1505 | with mock.patch("market.ReportStore"): | ||
1506 | m = market.Market(self.ccxt, self.market_args()) | ||
1507 | |||
1508 | value_from = portfolio.Amount("BTC", "1.0") | ||
1509 | value_from.linked_to = portfolio.Amount("ETH", "10.0") | ||
1510 | value_to = portfolio.Amount("BTC", "10.0") | ||
1511 | trade1 = portfolio.Trade(value_from, value_to, "ETH", m) | ||
1512 | |||
1513 | value_from = portfolio.Amount("BTC", "0.0") | ||
1514 | value_from.linked_to = portfolio.Amount("ETH", "0.0") | ||
1515 | value_to = portfolio.Amount("BTC", "-3.0") | ||
1516 | trade2 = portfolio.Trade(value_from, value_to, "ETH", m) | ||
1517 | |||
1518 | value_from = portfolio.Amount("USDT", "0.0") | ||
1519 | value_from.linked_to = portfolio.Amount("XVG", "0.0") | ||
1520 | value_to = portfolio.Amount("USDT", "-50.0") | ||
1521 | trade3 = portfolio.Trade(value_from, value_to, "XVG", m) | ||
1522 | |||
1523 | m.trades.all = [trade1, trade2, trade3] | ||
1524 | balance1 = portfolio.Balance("BTC", { "margin_in_position": "0", "margin_available": "0" }) | ||
1525 | balance2 = portfolio.Balance("USDT", { "margin_in_position": "100", "margin_available": "50" }) | ||
1526 | balance3 = portfolio.Balance("ETC", { "margin_in_position": "10", "margin_available": "15" }) | ||
1527 | m.balances.all = {"BTC": balance1, "USDT": balance2, "ETC": balance3} | ||
1528 | |||
1529 | call_counts = { "BTC": 0, "USDT": 0, "ETC": 0 } | ||
1530 | def _transfer_balance(currency, amount, from_, to_): | ||
1531 | call_counts[currency] += 1 | ||
1532 | if currency == "BTC": | ||
1533 | m.balances.all["BTC"] = portfolio.Balance("BTC", { "margin_in_position": "0", "margin_available": "3" }) | ||
1534 | if currency == "USDT": | ||
1535 | if call_counts["USDT"] == 1: | ||
1536 | raise market.ccxt.RequestTimeout | ||
1537 | else: | ||
1538 | m.balances.all["USDT"] = portfolio.Balance("USDT", { "margin_in_position": "100", "margin_available": "150" }) | ||
1539 | if currency == "ETC": | ||
1540 | m.balances.all["ETC"] = portfolio.Balance("ETC", { "margin_in_position": "10", "margin_available": "10" }) | ||
1541 | |||
1542 | |||
1543 | m.ccxt.transfer_balance.side_effect = _transfer_balance | ||
1544 | |||
1545 | m.move_balances() | ||
1546 | self.ccxt.transfer_balance.assert_has_calls([ | ||
1547 | mock.call("BTC", 3, "exchange", "margin"), | ||
1548 | mock.call('USDT', 100, 'exchange', 'margin'), | ||
1549 | mock.call('USDT', 100, 'exchange', 'margin'), | ||
1550 | mock.call("ETC", 5, "margin", "exchange") | ||
1551 | ]) | ||
1552 | self.assertEqual(2, fetch_balances.call_count) | ||
1553 | m.report.log_error.assert_called_with(mock.ANY, message="Retrying", exception=mock.ANY) | ||
1554 | self.assertEqual(2, m.report.log_move_balances.call_count) | ||
1555 | m.report.log_move_balances.asser_has_calls([ | ||
1556 | mock.call( | ||
1557 | { | ||
1558 | 'BTC': portfolio.Amount("BTC", "3"), | ||
1559 | 'USDT': portfolio.Amount("USDT", "150"), | ||
1560 | 'ETC': portfolio.Amount("ETC", "10"), | ||
1561 | }, | ||
1562 | { | ||
1563 | 'BTC': portfolio.Amount("BTC", "3"), | ||
1564 | 'USDT': portfolio.Amount("USDT", "100"), | ||
1565 | }), | ||
1566 | mock.call( | ||
1567 | { | ||
1568 | 'BTC': portfolio.Amount("BTC", "3"), | ||
1569 | 'USDT': portfolio.Amount("USDT", "150"), | ||
1570 | 'ETC': portfolio.Amount("ETC", "10"), | ||
1571 | }, | ||
1572 | { | ||
1573 | 'BTC': portfolio.Amount("BTC", "0"), | ||
1574 | 'USDT': portfolio.Amount("USDT", "100"), | ||
1575 | 'ETC': portfolio.Amount("ETC", "-5"), | ||
1576 | }), | ||
1577 | ]) | ||
1578 | |||
1579 | |||
1447 | def test_store_file_report(self): | 1580 | def test_store_file_report(self): |
1448 | file_open = mock.mock_open() | 1581 | file_open = mock.mock_open() |
1449 | m = market.Market(self.ccxt, self.market_args(), report_path="present", user_id=1) | 1582 | m = market.Market(self.ccxt, self.market_args(), report_path="present", user_id=1) |
@@ -3080,6 +3213,507 @@ class OrderTest(WebMockTestCase): | |||
3080 | self.assertEqual(5, self.m.report.log_error.call_count) | 3213 | self.assertEqual(5, self.m.report.log_error.call_count) |
3081 | self.m.report.log_error.assert_called_with(mock.ANY, message="Giving up Order(buy long 0.00096060 ETH at 0.1 BTC [pending])", exception=mock.ANY) | 3214 | self.m.report.log_error.assert_called_with(mock.ANY, message="Giving up Order(buy long 0.00096060 ETH at 0.1 BTC [pending])", exception=mock.ANY) |
3082 | 3215 | ||
3216 | self.m.reset_mock() | ||
3217 | with self.subTest(request_timeout=True): | ||
3218 | order = portfolio.Order("buy", portfolio.Amount("ETH", "0.001"), | ||
3219 | D("0.1"), "BTC", "long", self.m, "trade") | ||
3220 | with self.subTest(retrieved=False), \ | ||
3221 | mock.patch.object(order, "retrieve_order") as retrieve: | ||
3222 | self.m.ccxt.create_order.side_effect = [ | ||
3223 | portfolio.RequestTimeout, | ||
3224 | portfolio.RequestTimeout, | ||
3225 | { "id": 123 }, | ||
3226 | ] | ||
3227 | retrieve.return_value = False | ||
3228 | order.run() | ||
3229 | self.m.ccxt.create_order.assert_has_calls([ | ||
3230 | mock.call('ETH/BTC', 'limit', 'buy', D('0.0010'), account='exchange', price=D('0.1')), | ||
3231 | mock.call('ETH/BTC', 'limit', 'buy', D('0.0010'), account='exchange', price=D('0.1')), | ||
3232 | mock.call('ETH/BTC', 'limit', 'buy', D('0.0010'), account='exchange', price=D('0.1')), | ||
3233 | ]) | ||
3234 | self.assertEqual(3, self.m.ccxt.create_order.call_count) | ||
3235 | self.assertEqual(3, order.tries) | ||
3236 | self.m.report.log_error.assert_called() | ||
3237 | self.assertEqual(2, self.m.report.log_error.call_count) | ||
3238 | self.m.report.log_error.assert_called_with(mock.ANY, message="Retrying after timeout", exception=mock.ANY) | ||
3239 | self.assertEqual(123, order.id) | ||
3240 | |||
3241 | self.m.reset_mock() | ||
3242 | order = portfolio.Order("buy", portfolio.Amount("ETH", "0.001"), | ||
3243 | D("0.1"), "BTC", "long", self.m, "trade") | ||
3244 | with self.subTest(retrieved=True), \ | ||
3245 | mock.patch.object(order, "retrieve_order") as retrieve: | ||
3246 | self.m.ccxt.create_order.side_effect = [ | ||
3247 | portfolio.RequestTimeout, | ||
3248 | ] | ||
3249 | def _retrieve(): | ||
3250 | order.results.append({"id": 123}) | ||
3251 | return True | ||
3252 | retrieve.side_effect = _retrieve | ||
3253 | order.run() | ||
3254 | self.m.ccxt.create_order.assert_has_calls([ | ||
3255 | mock.call('ETH/BTC', 'limit', 'buy', D('0.0010'), account='exchange', price=D('0.1')), | ||
3256 | ]) | ||
3257 | self.assertEqual(1, self.m.ccxt.create_order.call_count) | ||
3258 | self.assertEqual(1, order.tries) | ||
3259 | self.m.report.log_error.assert_called() | ||
3260 | self.assertEqual(1, self.m.report.log_error.call_count) | ||
3261 | self.m.report.log_error.assert_called_with(mock.ANY, message="Timeout, found the order") | ||
3262 | self.assertEqual(123, order.id) | ||
3263 | |||
3264 | self.m.reset_mock() | ||
3265 | order = portfolio.Order("buy", portfolio.Amount("ETH", "0.001"), | ||
3266 | D("0.1"), "BTC", "long", self.m, "trade") | ||
3267 | with self.subTest(retrieved=False), \ | ||
3268 | mock.patch.object(order, "retrieve_order") as retrieve: | ||
3269 | self.m.ccxt.create_order.side_effect = [ | ||
3270 | portfolio.RequestTimeout, | ||
3271 | portfolio.RequestTimeout, | ||
3272 | portfolio.RequestTimeout, | ||
3273 | portfolio.RequestTimeout, | ||
3274 | portfolio.RequestTimeout, | ||
3275 | ] | ||
3276 | retrieve.return_value = False | ||
3277 | order.run() | ||
3278 | self.m.ccxt.create_order.assert_has_calls([ | ||
3279 | mock.call('ETH/BTC', 'limit', 'buy', D('0.0010'), account='exchange', price=D('0.1')), | ||
3280 | mock.call('ETH/BTC', 'limit', 'buy', D('0.0010'), account='exchange', price=D('0.1')), | ||
3281 | mock.call('ETH/BTC', 'limit', 'buy', D('0.0010'), account='exchange', price=D('0.1')), | ||
3282 | mock.call('ETH/BTC', 'limit', 'buy', D('0.0010'), account='exchange', price=D('0.1')), | ||
3283 | mock.call('ETH/BTC', 'limit', 'buy', D('0.0010'), account='exchange', price=D('0.1')), | ||
3284 | ]) | ||
3285 | self.assertEqual(5, self.m.ccxt.create_order.call_count) | ||
3286 | self.assertEqual(5, order.tries) | ||
3287 | self.m.report.log_error.assert_called() | ||
3288 | self.assertEqual(5, self.m.report.log_error.call_count) | ||
3289 | self.m.report.log_error.assert_called_with(mock.ANY, message="Giving up Order(buy long 0.00100000 ETH at 0.1 BTC [pending]) after timeouts", exception=mock.ANY) | ||
3290 | self.assertEqual("error", order.status) | ||
3291 | |||
3292 | def test_retrieve_order(self): | ||
3293 | with self.subTest(similar_open_order=True): | ||
3294 | order = portfolio.Order("buy", portfolio.Amount("ETH", "0.001"), | ||
3295 | D("0.1"), "BTC", "long", self.m, "trade") | ||
3296 | order.start_date = datetime.datetime(2018, 3, 25, 15, 15, 55) | ||
3297 | |||
3298 | self.m.ccxt.order_precision.return_value = 8 | ||
3299 | self.m.ccxt.fetch_orders.return_value = [ | ||
3300 | { # Wrong amount | ||
3301 | 'amount': 0.002, 'cost': 0.1, | ||
3302 | 'datetime': '2018-03-25T15:15:51.000Z', | ||
3303 | 'fee': None, 'filled': 0.0, | ||
3304 | 'id': '1', | ||
3305 | 'info': { | ||
3306 | 'amount': '0.002', | ||
3307 | 'date': '2018-03-25 15:15:51', | ||
3308 | 'margin': 0, 'orderNumber': '1', | ||
3309 | 'price': '0.1', 'rate': '0.1', | ||
3310 | 'side': 'buy', 'startingAmount': '0.002', | ||
3311 | 'status': 'open', 'total': '0.0002', | ||
3312 | 'type': 'limit' | ||
3313 | }, | ||
3314 | 'price': 0.1, 'remaining': 0.002, 'side': 'buy', | ||
3315 | 'status': 'open', 'symbol': 'ETH/BTC', | ||
3316 | 'timestamp': 1521990951000, 'trades': None, | ||
3317 | 'type': 'limit' | ||
3318 | }, | ||
3319 | { # Margin | ||
3320 | 'amount': 0.001, 'cost': 0.1, | ||
3321 | 'datetime': '2018-03-25T15:15:51.000Z', | ||
3322 | 'fee': None, 'filled': 0.0, | ||
3323 | 'id': '2', | ||
3324 | 'info': { | ||
3325 | 'amount': '0.001', | ||
3326 | 'date': '2018-03-25 15:15:51', | ||
3327 | 'margin': 1, 'orderNumber': '2', | ||
3328 | 'price': '0.1', 'rate': '0.1', | ||
3329 | 'side': 'buy', 'startingAmount': '0.001', | ||
3330 | 'status': 'open', 'total': '0.0001', | ||
3331 | 'type': 'limit' | ||
3332 | }, | ||
3333 | 'price': 0.1, 'remaining': 0.001, 'side': 'buy', | ||
3334 | 'status': 'open', 'symbol': 'ETH/BTC', | ||
3335 | 'timestamp': 1521990951000, 'trades': None, | ||
3336 | 'type': 'limit' | ||
3337 | }, | ||
3338 | { # selling | ||
3339 | 'amount': 0.001, 'cost': 0.1, | ||
3340 | 'datetime': '2018-03-25T15:15:51.000Z', | ||
3341 | 'fee': None, 'filled': 0.0, | ||
3342 | 'id': '3', | ||
3343 | 'info': { | ||
3344 | 'amount': '0.001', | ||
3345 | 'date': '2018-03-25 15:15:51', | ||
3346 | 'margin': 0, 'orderNumber': '3', | ||
3347 | 'price': '0.1', 'rate': '0.1', | ||
3348 | 'side': 'sell', 'startingAmount': '0.001', | ||
3349 | 'status': 'open', 'total': '0.0001', | ||
3350 | 'type': 'limit' | ||
3351 | }, | ||
3352 | 'price': 0.1, 'remaining': 0.001, 'side': 'sell', | ||
3353 | 'status': 'open', 'symbol': 'ETH/BTC', | ||
3354 | 'timestamp': 1521990951000, 'trades': None, | ||
3355 | 'type': 'limit' | ||
3356 | }, | ||
3357 | { # Wrong rate | ||
3358 | 'amount': 0.001, 'cost': 0.15, | ||
3359 | 'datetime': '2018-03-25T15:15:51.000Z', | ||
3360 | 'fee': None, 'filled': 0.0, | ||
3361 | 'id': '4', | ||
3362 | 'info': { | ||
3363 | 'amount': '0.001', | ||
3364 | 'date': '2018-03-25 15:15:51', | ||
3365 | 'margin': 0, 'orderNumber': '4', | ||
3366 | 'price': '0.15', 'rate': '0.15', | ||
3367 | 'side': 'buy', 'startingAmount': '0.001', | ||
3368 | 'status': 'open', 'total': '0.0001', | ||
3369 | 'type': 'limit' | ||
3370 | }, | ||
3371 | 'price': 0.15, 'remaining': 0.001, 'side': 'buy', | ||
3372 | 'status': 'open', 'symbol': 'ETH/BTC', | ||
3373 | 'timestamp': 1521990951000, 'trades': None, | ||
3374 | 'type': 'limit' | ||
3375 | }, | ||
3376 | { # All good | ||
3377 | 'amount': 0.001, 'cost': 0.1, | ||
3378 | 'datetime': '2018-03-25T15:15:51.000Z', | ||
3379 | 'fee': None, 'filled': 0.0, | ||
3380 | 'id': '5', | ||
3381 | 'info': { | ||
3382 | 'amount': '0.001', | ||
3383 | 'date': '2018-03-25 15:15:51', | ||
3384 | 'margin': 0, 'orderNumber': '1', | ||
3385 | 'price': '0.1', 'rate': '0.1', | ||
3386 | 'side': 'buy', 'startingAmount': '0.001', | ||
3387 | 'status': 'open', 'total': '0.0001', | ||
3388 | 'type': 'limit' | ||
3389 | }, | ||
3390 | 'price': 0.1, 'remaining': 0.001, 'side': 'buy', | ||
3391 | 'status': 'open', 'symbol': 'ETH/BTC', | ||
3392 | 'timestamp': 1521990951000, 'trades': None, | ||
3393 | 'type': 'limit' | ||
3394 | } | ||
3395 | ] | ||
3396 | result = order.retrieve_order() | ||
3397 | self.assertTrue(result) | ||
3398 | self.assertEqual('5', order.results[0]["id"]) | ||
3399 | self.m.ccxt.fetch_my_trades.assert_not_called() | ||
3400 | self.m.ccxt.fetch_orders.assert_called_once_with(symbol="ETH/BTC", since=1521983750) | ||
3401 | |||
3402 | self.m.reset_mock() | ||
3403 | with self.subTest(similar_open_order=False, past_trades=True): | ||
3404 | order = portfolio.Order("buy", portfolio.Amount("ETH", "0.001"), | ||
3405 | D("0.1"), "BTC", "long", self.m, "trade") | ||
3406 | order.start_date = datetime.datetime(2018, 3, 25, 15, 15, 55) | ||
3407 | |||
3408 | self.m.ccxt.order_precision.return_value = 8 | ||
3409 | self.m.ccxt.fetch_orders.return_value = [] | ||
3410 | self.m.ccxt.fetch_my_trades.return_value = [ | ||
3411 | { # Wrong timestamp 1 | ||
3412 | 'amount': 0.0006, | ||
3413 | 'cost': 0.00006, | ||
3414 | 'datetime': '2018-03-25T15:15:14.000Z', | ||
3415 | 'id': '1-1', | ||
3416 | 'info': { | ||
3417 | 'amount': '0.0006', | ||
3418 | 'category': 'exchange', | ||
3419 | 'date': '2018-03-25 15:15:14', | ||
3420 | 'fee': '0.00150000', | ||
3421 | 'globalTradeID': 1, | ||
3422 | 'orderNumber': '1', | ||
3423 | 'rate': '0.1', | ||
3424 | 'total': '0.00006', | ||
3425 | 'tradeID': '1-1', | ||
3426 | 'type': 'buy' | ||
3427 | }, | ||
3428 | 'order': '1', | ||
3429 | 'price': 0.1, | ||
3430 | 'side': 'buy', | ||
3431 | 'symbol': 'ETH/BTC', | ||
3432 | 'timestamp': 1521983714, | ||
3433 | 'type': 'limit' | ||
3434 | }, | ||
3435 | { # Wrong timestamp 2 | ||
3436 | 'amount': 0.0004, | ||
3437 | 'cost': 0.00004, | ||
3438 | 'datetime': '2018-03-25T15:16:54.000Z', | ||
3439 | 'id': '1-2', | ||
3440 | 'info': { | ||
3441 | 'amount': '0.0004', | ||
3442 | 'category': 'exchange', | ||
3443 | 'date': '2018-03-25 15:16:54', | ||
3444 | 'fee': '0.00150000', | ||
3445 | 'globalTradeID': 2, | ||
3446 | 'orderNumber': '1', | ||
3447 | 'rate': '0.1', | ||
3448 | 'total': '0.00004', | ||
3449 | 'tradeID': '1-2', | ||
3450 | 'type': 'buy' | ||
3451 | }, | ||
3452 | 'order': '1', | ||
3453 | 'price': 0.1, | ||
3454 | 'side': 'buy', | ||
3455 | 'symbol': 'ETH/BTC', | ||
3456 | 'timestamp': 1521983814, | ||
3457 | 'type': 'limit' | ||
3458 | }, | ||
3459 | { # Wrong side 1 | ||
3460 | 'amount': 0.0006, | ||
3461 | 'cost': 0.00006, | ||
3462 | 'datetime': '2018-03-25T15:15:54.000Z', | ||
3463 | 'id': '2-1', | ||
3464 | 'info': { | ||
3465 | 'amount': '0.0006', | ||
3466 | 'category': 'exchange', | ||
3467 | 'date': '2018-03-25 15:15:54', | ||
3468 | 'fee': '0.00150000', | ||
3469 | 'globalTradeID': 1, | ||
3470 | 'orderNumber': '2', | ||
3471 | 'rate': '0.1', | ||
3472 | 'total': '0.00006', | ||
3473 | 'tradeID': '2-1', | ||
3474 | 'type': 'sell' | ||
3475 | }, | ||
3476 | 'order': '2', | ||
3477 | 'price': 0.1, | ||
3478 | 'side': 'sell', | ||
3479 | 'symbol': 'ETH/BTC', | ||
3480 | 'timestamp': 1521983754, | ||
3481 | 'type': 'limit' | ||
3482 | }, | ||
3483 | { # Wrong side 2 | ||
3484 | 'amount': 0.0004, | ||
3485 | 'cost': 0.00004, | ||
3486 | 'datetime': '2018-03-25T15:16:54.000Z', | ||
3487 | 'id': '2-2', | ||
3488 | 'info': { | ||
3489 | 'amount': '0.0004', | ||
3490 | 'category': 'exchange', | ||
3491 | 'date': '2018-03-25 15:16:54', | ||
3492 | 'fee': '0.00150000', | ||
3493 | 'globalTradeID': 2, | ||
3494 | 'orderNumber': '2', | ||
3495 | 'rate': '0.1', | ||
3496 | 'total': '0.00004', | ||
3497 | 'tradeID': '2-2', | ||
3498 | 'type': 'buy' | ||
3499 | }, | ||
3500 | 'order': '2', | ||
3501 | 'price': 0.1, | ||
3502 | 'side': 'buy', | ||
3503 | 'symbol': 'ETH/BTC', | ||
3504 | 'timestamp': 1521983814, | ||
3505 | 'type': 'limit' | ||
3506 | }, | ||
3507 | { # Margin trade 1 | ||
3508 | 'amount': 0.0006, | ||
3509 | 'cost': 0.00006, | ||
3510 | 'datetime': '2018-03-25T15:15:54.000Z', | ||
3511 | 'id': '3-1', | ||
3512 | 'info': { | ||
3513 | 'amount': '0.0006', | ||
3514 | 'category': 'marginTrade', | ||
3515 | 'date': '2018-03-25 15:15:54', | ||
3516 | 'fee': '0.00150000', | ||
3517 | 'globalTradeID': 1, | ||
3518 | 'orderNumber': '3', | ||
3519 | 'rate': '0.1', | ||
3520 | 'total': '0.00006', | ||
3521 | 'tradeID': '3-1', | ||
3522 | 'type': 'buy' | ||
3523 | }, | ||
3524 | 'order': '3', | ||
3525 | 'price': 0.1, | ||
3526 | 'side': 'buy', | ||
3527 | 'symbol': 'ETH/BTC', | ||
3528 | 'timestamp': 1521983754, | ||
3529 | 'type': 'limit' | ||
3530 | }, | ||
3531 | { # Margin trade 2 | ||
3532 | 'amount': 0.0004, | ||
3533 | 'cost': 0.00004, | ||
3534 | 'datetime': '2018-03-25T15:16:54.000Z', | ||
3535 | 'id': '3-2', | ||
3536 | 'info': { | ||
3537 | 'amount': '0.0004', | ||
3538 | 'category': 'marginTrade', | ||
3539 | 'date': '2018-03-25 15:16:54', | ||
3540 | 'fee': '0.00150000', | ||
3541 | 'globalTradeID': 2, | ||
3542 | 'orderNumber': '3', | ||
3543 | 'rate': '0.1', | ||
3544 | 'total': '0.00004', | ||
3545 | 'tradeID': '3-2', | ||
3546 | 'type': 'buy' | ||
3547 | }, | ||
3548 | 'order': '3', | ||
3549 | 'price': 0.1, | ||
3550 | 'side': 'buy', | ||
3551 | 'symbol': 'ETH/BTC', | ||
3552 | 'timestamp': 1521983814, | ||
3553 | 'type': 'limit' | ||
3554 | }, | ||
3555 | { # Wrong amount 1 | ||
3556 | 'amount': 0.0005, | ||
3557 | 'cost': 0.00005, | ||
3558 | 'datetime': '2018-03-25T15:15:54.000Z', | ||
3559 | 'id': '4-1', | ||
3560 | 'info': { | ||
3561 | 'amount': '0.0005', | ||
3562 | 'category': 'exchange', | ||
3563 | 'date': '2018-03-25 15:15:54', | ||
3564 | 'fee': '0.00150000', | ||
3565 | 'globalTradeID': 1, | ||
3566 | 'orderNumber': '4', | ||
3567 | 'rate': '0.1', | ||
3568 | 'total': '0.00005', | ||
3569 | 'tradeID': '4-1', | ||
3570 | 'type': 'buy' | ||
3571 | }, | ||
3572 | 'order': '4', | ||
3573 | 'price': 0.1, | ||
3574 | 'side': 'buy', | ||
3575 | 'symbol': 'ETH/BTC', | ||
3576 | 'timestamp': 1521983754, | ||
3577 | 'type': 'limit' | ||
3578 | }, | ||
3579 | { # Wrong amount 2 | ||
3580 | 'amount': 0.0004, | ||
3581 | 'cost': 0.00004, | ||
3582 | 'datetime': '2018-03-25T15:16:54.000Z', | ||
3583 | 'id': '4-2', | ||
3584 | 'info': { | ||
3585 | 'amount': '0.0004', | ||
3586 | 'category': 'exchange', | ||
3587 | 'date': '2018-03-25 15:16:54', | ||
3588 | 'fee': '0.00150000', | ||
3589 | 'globalTradeID': 2, | ||
3590 | 'orderNumber': '4', | ||
3591 | 'rate': '0.1', | ||
3592 | 'total': '0.00004', | ||
3593 | 'tradeID': '4-2', | ||
3594 | 'type': 'buy' | ||
3595 | }, | ||
3596 | 'order': '4', | ||
3597 | 'price': 0.1, | ||
3598 | 'side': 'buy', | ||
3599 | 'symbol': 'ETH/BTC', | ||
3600 | 'timestamp': 1521983814, | ||
3601 | 'type': 'limit' | ||
3602 | }, | ||
3603 | { # Wrong price 1 | ||
3604 | 'amount': 0.0006, | ||
3605 | 'cost': 0.000066, | ||
3606 | 'datetime': '2018-03-25T15:15:54.000Z', | ||
3607 | 'id': '5-1', | ||
3608 | 'info': { | ||
3609 | 'amount': '0.0006', | ||
3610 | 'category': 'exchange', | ||
3611 | 'date': '2018-03-25 15:15:54', | ||
3612 | 'fee': '0.00150000', | ||
3613 | 'globalTradeID': 1, | ||
3614 | 'orderNumber': '5', | ||
3615 | 'rate': '0.11', | ||
3616 | 'total': '0.000066', | ||
3617 | 'tradeID': '5-1', | ||
3618 | 'type': 'buy' | ||
3619 | }, | ||
3620 | 'order': '5', | ||
3621 | 'price': 0.11, | ||
3622 | 'side': 'buy', | ||
3623 | 'symbol': 'ETH/BTC', | ||
3624 | 'timestamp': 1521983754, | ||
3625 | 'type': 'limit' | ||
3626 | }, | ||
3627 | { # Wrong price 2 | ||
3628 | 'amount': 0.0004, | ||
3629 | 'cost': 0.00004, | ||
3630 | 'datetime': '2018-03-25T15:16:54.000Z', | ||
3631 | 'id': '5-2', | ||
3632 | 'info': { | ||
3633 | 'amount': '0.0004', | ||
3634 | 'category': 'exchange', | ||
3635 | 'date': '2018-03-25 15:16:54', | ||
3636 | 'fee': '0.00150000', | ||
3637 | 'globalTradeID': 2, | ||
3638 | 'orderNumber': '5', | ||
3639 | 'rate': '0.1', | ||
3640 | 'total': '0.00004', | ||
3641 | 'tradeID': '5-2', | ||
3642 | 'type': 'buy' | ||
3643 | }, | ||
3644 | 'order': '5', | ||
3645 | 'price': 0.1, | ||
3646 | 'side': 'buy', | ||
3647 | 'symbol': 'ETH/BTC', | ||
3648 | 'timestamp': 1521983814, | ||
3649 | 'type': 'limit' | ||
3650 | }, | ||
3651 | { # All good 1 | ||
3652 | 'amount': 0.0006, | ||
3653 | 'cost': 0.00006, | ||
3654 | 'datetime': '2018-03-25T15:15:54.000Z', | ||
3655 | 'id': '7-1', | ||
3656 | 'info': { | ||
3657 | 'amount': '0.0006', | ||
3658 | 'category': 'exchange', | ||
3659 | 'date': '2018-03-25 15:15:54', | ||
3660 | 'fee': '0.00150000', | ||
3661 | 'globalTradeID': 1, | ||
3662 | 'orderNumber': '7', | ||
3663 | 'rate': '0.1', | ||
3664 | 'total': '0.00006', | ||
3665 | 'tradeID': '7-1', | ||
3666 | 'type': 'buy' | ||
3667 | }, | ||
3668 | 'order': '7', | ||
3669 | 'price': 0.1, | ||
3670 | 'side': 'buy', | ||
3671 | 'symbol': 'ETH/BTC', | ||
3672 | 'timestamp': 1521983754, | ||
3673 | 'type': 'limit' | ||
3674 | }, | ||
3675 | { # All good 2 | ||
3676 | 'amount': 0.0004, | ||
3677 | 'cost': 0.000036, | ||
3678 | 'datetime': '2018-03-25T15:16:54.000Z', | ||
3679 | 'id': '7-2', | ||
3680 | 'info': { | ||
3681 | 'amount': '0.0004', | ||
3682 | 'category': 'exchange', | ||
3683 | 'date': '2018-03-25 15:16:54', | ||
3684 | 'fee': '0.00150000', | ||
3685 | 'globalTradeID': 2, | ||
3686 | 'orderNumber': '7', | ||
3687 | 'rate': '0.09', | ||
3688 | 'total': '0.000036', | ||
3689 | 'tradeID': '7-2', | ||
3690 | 'type': 'buy' | ||
3691 | }, | ||
3692 | 'order': '7', | ||
3693 | 'price': 0.09, | ||
3694 | 'side': 'buy', | ||
3695 | 'symbol': 'ETH/BTC', | ||
3696 | 'timestamp': 1521983814, | ||
3697 | 'type': 'limit' | ||
3698 | }, | ||
3699 | ] | ||
3700 | |||
3701 | result = order.retrieve_order() | ||
3702 | self.assertTrue(result) | ||
3703 | self.assertEqual('7', order.results[0]["id"]) | ||
3704 | self.m.ccxt.fetch_orders.assert_called_once_with(symbol="ETH/BTC", since=1521983750) | ||
3705 | |||
3706 | self.m.reset_mock() | ||
3707 | with self.subTest(similar_open_order=False, past_trades=False): | ||
3708 | order = portfolio.Order("buy", portfolio.Amount("ETH", "0.001"), | ||
3709 | D("0.1"), "BTC", "long", self.m, "trade") | ||
3710 | order.start_date = datetime.datetime(2018, 3, 25, 15, 15, 55) | ||
3711 | |||
3712 | self.m.ccxt.order_precision.return_value = 8 | ||
3713 | self.m.ccxt.fetch_orders.return_value = [] | ||
3714 | self.m.ccxt.fetch_my_trades.return_value = [] | ||
3715 | result = order.retrieve_order() | ||
3716 | self.assertFalse(result) | ||
3083 | 3717 | ||
3084 | @unittest.skipUnless("unit" in limits, "Unit skipped") | 3718 | @unittest.skipUnless("unit" in limits, "Unit skipped") |
3085 | class MouvementTest(WebMockTestCase): | 3719 | class MouvementTest(WebMockTestCase): |