3 from decimal
import Decimal
as D
4 from unittest
import mock
6 class AmountTest(unittest
.TestCase
):
8 amount
= portfolio
.Amount("BTC", "0.65")
9 self
.assertEqual(D("0.65"), amount
.value
)
10 self
.assertEqual("BTC", amount
.currency
)
12 def test_in_currency(self
):
13 amount
= portfolio
.Amount("ETC", 10)
15 self
.assertEqual(amount
, amount
.in_currency("ETC", None))
17 ticker_mock
= unittest
.mock
.Mock()
18 with mock
.patch
.object(portfolio
.Trade
, 'get_ticker', new
=ticker_mock
):
19 ticker_mock
.return_value
= None
21 self
.assertRaises(Exception, amount
.in_currency
, "ETH", None)
23 with mock
.patch
.object(portfolio
.Trade
, 'get_ticker', new
=ticker_mock
):
24 ticker_mock
.return_value
= {
30 converted_amount
= amount
.in_currency("ETH", None)
32 self
.assertEqual(D("3.0"), converted_amount
.value
)
33 self
.assertEqual("ETH", converted_amount
.currency
)
34 self
.assertEqual(amount
, converted_amount
.linked_to
)
35 self
.assertEqual("bar", converted_amount
.ticker
["foo"])
37 converted_amount
= amount
.in_currency("ETH", None, action
="bid", compute_value
="default")
38 self
.assertEqual(D("2"), converted_amount
.value
)
40 converted_amount
= amount
.in_currency("ETH", None, compute_value
="ask")
41 self
.assertEqual(D("4"), converted_amount
.value
)
43 converted_amount
= amount
.in_currency("ETH", None, rate
=D("0.02"))
44 self
.assertEqual(D("0.2"), converted_amount
.value
)
47 amount
= portfolio
.Amount("SC", -120)
48 self
.assertEqual(120, abs(amount
).value
)
49 self
.assertEqual("SC", abs(amount
).currency
)
51 amount
= portfolio
.Amount("SC", 10)
52 self
.assertEqual(10, abs(amount
).value
)
53 self
.assertEqual("SC", abs(amount
).currency
)
56 amount1
= portfolio
.Amount("XVG", "12.9")
57 amount2
= portfolio
.Amount("XVG", "13.1")
59 self
.assertEqual(26, (amount1
+ amount2
).value
)
60 self
.assertEqual("XVG", (amount1
+ amount2
).currency
)
62 amount3
= portfolio
.Amount("ETH", "1.6")
63 with self
.assertRaises(Exception):
66 amount4
= portfolio
.Amount("ETH", 0.0)
67 self
.assertEqual(amount1
, amount1
+ amount4
)
70 amount
= portfolio
.Amount("XVG", "12.9")
72 self
.assertEqual(amount
, 0 + amount
)
73 with self
.assertRaises(Exception):
77 amount1
= portfolio
.Amount("XVG", "13.3")
78 amount2
= portfolio
.Amount("XVG", "13.1")
80 self
.assertEqual(D("0.2"), (amount1
- amount2
).value
)
81 self
.assertEqual("XVG", (amount1
- amount2
).currency
)
83 amount3
= portfolio
.Amount("ETH", "1.6")
84 with self
.assertRaises(Exception):
87 amount4
= portfolio
.Amount("ETH", 0.0)
88 self
.assertEqual(amount1
, amount1
- amount4
)
91 amount
= portfolio
.Amount("XEM", 11)
93 self
.assertEqual(D("38.5"), (amount
* D("3.5")).value
)
94 self
.assertEqual(D("33"), (amount
* 3).value
)
96 with self
.assertRaises(Exception):
100 amount
= portfolio
.Amount("XEM", 11)
102 self
.assertEqual(D("38.5"), (D("3.5") * amount
).value
)
103 self
.assertEqual(D("33"), (3 * amount
).value
)
105 def test__floordiv(self
):
106 amount
= portfolio
.Amount("XEM", 11)
108 self
.assertEqual(D("5.5"), (amount
/ 2).value
)
109 self
.assertEqual(D("4.4"), (amount
/ D("2.5")).value
)
112 amount
= portfolio
.Amount("XEM", 11)
114 self
.assertEqual(D("5.5"), (amount
/ 2).value
)
115 self
.assertEqual(D("4.4"), (amount
/ D("2.5")).value
)
118 amount1
= portfolio
.Amount("BTD", 11.3)
119 amount2
= portfolio
.Amount("BTD", 13.1)
121 self
.assertTrue(amount1
< amount2
)
122 self
.assertFalse(amount2
< amount1
)
123 self
.assertFalse(amount1
< amount1
)
125 amount3
= portfolio
.Amount("BTC", 1.6)
126 with self
.assertRaises(Exception):
130 amount1
= portfolio
.Amount("BTD", 11.3)
131 amount2
= portfolio
.Amount("BTD", 13.1)
132 amount3
= portfolio
.Amount("BTD", 11.3)
134 self
.assertFalse(amount1
== amount2
)
135 self
.assertFalse(amount2
== amount1
)
136 self
.assertTrue(amount1
== amount3
)
137 self
.assertFalse(amount2
== 0)
139 amount4
= portfolio
.Amount("BTC", 1.6)
140 with self
.assertRaises(Exception):
143 amount5
= portfolio
.Amount("BTD", 0)
144 self
.assertTrue(amount5
== 0)
147 amount1
= portfolio
.Amount("BTX", 32)
148 self
.assertEqual("32.00000000 BTX", str(amount1
))
150 amount2
= portfolio
.Amount("USDT", 12000)
151 amount1
.linked_to
= amount2
152 self
.assertEqual("32.00000000 BTX [12000.00000000 USDT]", str(amount1
))
154 def test__repr(self
):
155 amount1
= portfolio
.Amount("BTX", 32)
156 self
.assertEqual("Amount(32.00000000 BTX)", repr(amount1
))
158 amount2
= portfolio
.Amount("USDT", 12000)
159 amount1
.linked_to
= amount2
160 self
.assertEqual("Amount(32.00000000 BTX -> Amount(12000.00000000 USDT))", repr(amount1
))
162 amount3
= portfolio
.Amount("BTC", 0.1)
163 amount2
.linked_to
= amount3
164 self
.assertEqual("Amount(32.00000000 BTX -> Amount(12000.00000000 USDT -> Amount(0.10000000 BTC)))", repr(amount1
))
166 class PortfolioTest(unittest
.TestCase
):
169 if self
.json_response
is not None:
170 portfolio
.Portfolio
.data
= self
.json_response
173 super(PortfolioTest
, self
).setUp()
175 with open("test_portfolio.json") as example
:
177 self
.json_response
= json
.load(example
, parse_int
=portfolio
.D
, parse_float
=portfolio
.D
)
179 self
.patcher
= mock
.patch
.multiple(portfolio
.Portfolio
, data
=None, liquidities
={})
182 @mock.patch.object(urllib3
, "disable_warnings")
183 @mock.patch.object(urllib3
.poolmanager
.PoolManager
, "request")
184 @mock.patch.object(portfolio
.Portfolio
, "URL", new
="foo://bar")
185 def test_get_cryptoportfolio(self
, request
, disable_warnings
):
186 request
.side_effect
= [
187 type('', (), { "data": '{ "foo": "bar" }
' }),
188 type('', (), { "data": 'System Error' }),
189 Exception("Connection error"),
192 portfolio.Portfolio.get_cryptoportfolio()
193 self.assertIn("foo", portfolio.Portfolio.data)
194 self.assertEqual("bar", portfolio.Portfolio.data["foo"])
195 request.assert_called_with("GET", "foo://bar")
198 portfolio.Portfolio.get_cryptoportfolio()
199 self.assertIsNone(portfolio.Portfolio.data)
200 request.assert_called_with("GET", "foo://bar")
203 portfolio.Portfolio.data = "foo"
204 portfolio.Portfolio.get_cryptoportfolio()
205 request.assert_called_with("GET", "foo://bar")
206 self.assertEqual("foo", portfolio.Portfolio.data)
207 disable_warnings.assert_called_with()
209 @mock.patch.object(portfolio.Portfolio, "get_cryptoportfolio")
210 def test_parse_cryptoportfolio(self, mock_get):
211 mock_get.side_effect = self.fill_data
213 portfolio.Portfolio.parse_cryptoportfolio()
215 self.assertListEqual(
217 list(portfolio.Portfolio.liquidities.keys()))
219 liquidities = portfolio.Portfolio.liquidities
220 self.assertEqual(10, len(liquidities["medium"].keys()))
221 self.assertEqual(10, len(liquidities["high"].keys()))
224 'BTC
': (D("0.2857"), "long"),
225 'DGB
': (D("0.1015"), "long"),
226 'DOGE
': (D("0.1805"), "long"),
227 'SC
': (D("0.0623"), "long"),
228 'ZEC
': (D("0.3701"), "long"),
230 self.assertDictEqual(expected, liquidities["high"]['2018-01-08'])
233 'BTC
': (D("1.1102e-16"), "long"),
234 'ETC
': (D("0.1"), "long"),
235 'FCT
': (D("0.1"), "long"),
236 'GAS
': (D("0.1"), "long"),
237 'NAV
': (D("0.1"), "long"),
238 'OMG
': (D("0.1"), "long"),
239 'OMNI
': (D("0.1"), "long"),
240 'PPC
': (D("0.1"), "long"),
241 'RIC
': (D("0.1"), "long"),
242 'VIA
': (D("0.1"), "long"),
243 'XCP
': (D("0.1"), "long"),
245 self.assertDictEqual(expected, liquidities["medium"]['2018-01-08'])
247 # It doesn't refetch the data when available
248 portfolio
.Portfolio
.parse_cryptoportfolio()
249 mock_get
.assert_called_once_with()
251 @mock.patch.object(portfolio
.Portfolio
, "get_cryptoportfolio")
252 def test_repartition(self
, mock_get
):
253 mock_get
.side_effect
= self
.fill_data
256 'BTC': (D("1.1102e-16"), "long"),
257 'USDT': (D("0.1"), "long"),
258 'ETC': (D("0.1"), "long"),
259 'FCT': (D("0.1"), "long"),
260 'OMG': (D("0.1"), "long"),
261 'STEEM': (D("0.1"), "long"),
262 'STRAT': (D("0.1"), "long"),
263 'XEM': (D("0.1"), "long"),
264 'XMR': (D("0.1"), "long"),
265 'XVC': (D("0.1"), "long"),
266 'ZRX': (D("0.1"), "long"),
269 'USDT': (D("0.1226"), "long"),
270 'BTC': (D("0.1429"), "long"),
271 'ETC': (D("0.1127"), "long"),
272 'ETH': (D("0.1569"), "long"),
273 'FCT': (D("0.3341"), "long"),
274 'GAS': (D("0.1308"), "long"),
277 self
.assertEqual(expected_medium
, portfolio
.Portfolio
.repartition())
278 self
.assertEqual(expected_medium
, portfolio
.Portfolio
.repartition(liquidity
="medium"))
279 self
.assertEqual(expected_high
, portfolio
.Portfolio
.repartition(liquidity
="high"))
284 class BalanceTest(unittest
.TestCase
):
286 super(BalanceTest
, self
).setUp()
288 self
.fetch_balance
= {
314 self
.patcher
= mock
.patch
.multiple(portfolio
.Balance
, known_balances
={})
317 def test_values(self
):
318 balance
= portfolio
.Balance("BTC", 0.65, 0.35, 0.30)
319 self
.assertEqual(0.65, balance
.total
.value
)
320 self
.assertEqual(0.35, balance
.free
.value
)
321 self
.assertEqual(0.30, balance
.used
.value
)
322 self
.assertEqual("BTC", balance
.currency
)
324 balance
= portfolio
.Balance
.from_hash("BTC", { "total": 0.65, "free": 0.35, "used": 0.30}
)
325 self
.assertEqual(0.65, balance
.total
.value
)
326 self
.assertEqual(0.35, balance
.free
.value
)
327 self
.assertEqual(0.30, balance
.used
.value
)
328 self
.assertEqual("BTC", balance
.currency
)
330 @mock.patch.object(portfolio
.Trade
, "get_ticker")
331 def test_in_currency(self
, get_ticker
):
332 portfolio
.Balance
.known_balances
= {
333 "BTC": portfolio
.Balance("BTC", "0.65", "0.35", "0.30"),
334 "ETH": portfolio
.Balance("ETH", 3, 3, 0),
337 get_ticker
.return_value
= {
343 amounts
= portfolio
.Balance
.in_currency("BTC", market
)
344 self
.assertEqual("BTC", amounts
["ETH"].currency
)
345 self
.assertEqual(D("0.65"), amounts
["BTC"].value
)
346 self
.assertEqual(D("0.30"), amounts
["ETH"].value
)
348 amounts
= portfolio
.Balance
.in_currency("BTC", market
, compute_value
="bid")
349 self
.assertEqual(D("0.65"), amounts
["BTC"].value
)
350 self
.assertEqual(D("0.27"), amounts
["ETH"].value
)
352 amounts
= portfolio
.Balance
.in_currency("BTC", market
, compute_value
="bid", type="used")
353 self
.assertEqual(D("0.30"), amounts
["BTC"].value
)
354 self
.assertEqual(0, amounts
["ETH"].value
)
356 def test_currencies(self
):
357 portfolio
.Balance
.known_balances
= {
358 "BTC": portfolio
.Balance("BTC", "0.65", "0.35", "0.30"),
359 "ETH": portfolio
.Balance("ETH", 3, 3, 0),
361 self
.assertListEqual(["BTC", "ETH"], list(portfolio
.Balance
.currencies()))
363 @mock.patch.object(portfolio
.market
, "fetch_balance")
364 def test_fetch_balances(self
, fetch_balance
):
365 fetch_balance
.return_value
= self
.fetch_balance
367 portfolio
.Balance
.fetch_balances(portfolio
.market
)
368 self
.assertNotIn("XMR", portfolio
.Balance
.currencies())
369 self
.assertListEqual(["USDT", "XVG"], list(portfolio
.Balance
.currencies()))
371 portfolio
.Balance
.known_balances
["ETC"] = portfolio
.Balance("ETC", "1", "0", "1")
372 portfolio
.Balance
.fetch_balances(portfolio
.market
)
373 self
.assertEqual(0, portfolio
.Balance
.known_balances
["ETC"].total
)
374 self
.assertListEqual(["USDT", "XVG", "ETC"], list(portfolio
.Balance
.currencies()))
376 @mock.patch.object(portfolio
.Portfolio
, "repartition")
377 @mock.patch.object(portfolio
.market
, "fetch_balance")
378 def test_dispatch_assets(self
, fetch_balance
, repartition
):
379 fetch_balance
.return_value
= self
.fetch_balance
380 portfolio
.Balance
.fetch_balances(portfolio
.market
)
382 self
.assertNotIn("XEM", portfolio
.Balance
.currencies())
384 repartition
.return_value
= {
385 "XEM": (D("0.75"), "long"),
386 "BTC": (D("0.26"), "long"),
389 amounts
= portfolio
.Balance
.dispatch_assets(portfolio
.Amount("BTC", "10.1"))
390 self
.assertIn("XEM", portfolio
.Balance
.currencies())
391 self
.assertEqual(D("2.6"), amounts
["BTC"].value
)
392 self
.assertEqual(D("7.5"), amounts
["XEM"].value
)
394 @mock.patch.object(portfolio
.Portfolio
, "repartition")
395 @mock.patch.object(portfolio
.Trade
, "get_ticker")
396 @mock.patch.object(portfolio
.Trade
, "compute_trades")
397 def test_prepare_trades(self
, compute_trades
, get_ticker
, repartition
):
398 repartition
.return_value
= {
399 "XEM": (D("0.75"), "long"),
400 "BTC": (D("0.25"), "long"),
402 def _get_ticker(c1
, c2
, market
):
403 if c1
== "USDT" and c2
== "BTC":
404 return { "average": D("0.0001") }
405 if c1
== "XVG" and c2
== "BTC":
406 return { "average": D("0.000001") }
407 if c1
== "XEM" and c2
== "BTC":
408 return { "average": D("0.001") }
409 self
.fail("Should be called with {}, {}".format(c1
, c2
))
410 get_ticker
.side_effect
= _get_ticker
413 market
.fetch_balance
.return_value
= {
415 "free": D("10000.0"),
417 "total": D("10000.0")
420 "free": D("10000.0"),
422 "total": D("10000.0")
425 portfolio
.Balance
.prepare_trades(market
)
426 compute_trades
.assert_called()
428 call
= compute_trades
.call_args
429 self
.assertEqual(market
, call
[1]["market"])
430 self
.assertEqual(1, call
[0][0]["USDT"].value
)
431 self
.assertEqual(D("0.01"), call
[0][0]["XVG"].value
)
432 self
.assertEqual(D("0.2525"), call
[0][1]["BTC"].value
)
433 self
.assertEqual(D("0.7575"), call
[0][1]["XEM"].value
)
435 @unittest.skip("TODO")
436 def test_update_trades(self
):
439 def test__repr(self
):
440 balance
= portfolio
.Balance("BTX", 3, 1, 2)
441 self
.assertEqual("Balance(BTX [1.00000000 BTX/2.00000000 BTX/3.00000000 BTX])", repr(balance
))
446 class TradeTest(unittest
.TestCase
):
450 super(TradeTest
, self
).setUp()
452 self
.patcher
= mock
.patch
.multiple(portfolio
.Trade
,
454 ticker_cache_timestamp
=self
.time
.time(),
459 def test_get_ticker(self
):
461 market
.fetch_ticker
.side_effect
= [
462 { "bid": 1, "ask": 3 }
,
463 portfolio
.ExchangeError("foo"),
464 { "bid": 10, "ask": 40 }
,
465 portfolio
.ExchangeError("foo"),
466 portfolio
.ExchangeError("foo"),
469 ticker
= portfolio
.Trade
.get_ticker("ETH", "ETC", market
)
470 market
.fetch_ticker
.assert_called_with("ETH/ETC")
471 self
.assertEqual(1, ticker
["bid"])
472 self
.assertEqual(3, ticker
["ask"])
473 self
.assertEqual(2, ticker
["average"])
474 self
.assertFalse(ticker
["inverted"])
476 ticker
= portfolio
.Trade
.get_ticker("ETH", "XVG", market
)
477 self
.assertEqual(0.0625, ticker
["average"])
478 self
.assertTrue(ticker
["inverted"])
479 self
.assertIn("original", ticker
)
480 self
.assertEqual(10, ticker
["original"]["bid"])
482 ticker
= portfolio
.Trade
.get_ticker("XVG", "XMR", market
)
483 self
.assertIsNone(ticker
)
485 market
.fetch_ticker
.assert_has_calls([
486 mock
.call("ETH/ETC"),
487 mock
.call("ETH/XVG"),
488 mock
.call("XVG/ETH"),
489 mock
.call("XVG/XMR"),
490 mock
.call("XMR/XVG"),
493 market2
= mock
.Mock()
494 market2
.fetch_ticker
.side_effect
= [
495 { "bid": 1, "ask": 3 }
,
496 { "bid": 1.2, "ask": 3.5 }
,
498 ticker1
= portfolio
.Trade
.get_ticker("ETH", "ETC", market2
)
499 ticker2
= portfolio
.Trade
.get_ticker("ETH", "ETC", market2
)
500 ticker3
= portfolio
.Trade
.get_ticker("ETC", "ETH", market2
)
501 market2
.fetch_ticker
.assert_called_once_with("ETH/ETC")
502 self
.assertEqual(1, ticker1
["bid"])
503 self
.assertDictEqual(ticker1
, ticker2
)
504 self
.assertDictEqual(ticker1
, ticker3
["original"])
506 ticker4
= portfolio
.Trade
.get_ticker("ETH", "ETC", market2
, refresh
=True)
507 ticker5
= portfolio
.Trade
.get_ticker("ETH", "ETC", market2
)
508 self
.assertEqual(1.2, ticker4
["bid"])
509 self
.assertDictEqual(ticker4
, ticker5
)
511 market3
= mock
.Mock()
512 market3
.fetch_ticker
.side_effect
= [
513 { "bid": 1, "ask": 3 }
,
514 { "bid": 1.2, "ask": 3.5 }
,
516 ticker6
= portfolio
.Trade
.get_ticker("ETH", "ETC", market3
)
517 portfolio
.Trade
.ticker_cache_timestamp
-= 4
518 ticker7
= portfolio
.Trade
.get_ticker("ETH", "ETC", market3
)
519 portfolio
.Trade
.ticker_cache_timestamp
-= 2
520 ticker8
= portfolio
.Trade
.get_ticker("ETH", "ETC", market3
)
521 self
.assertDictEqual(ticker6
, ticker7
)
522 self
.assertEqual(1.2, ticker8
["bid"])
524 @unittest.skip("TODO")
525 def test_values_assertion(self
):
526 value_from
= Amount("BTC", "1.0")
527 value_from
.linked_to
= Amount("ETH", "10.0")
528 value_to
= Amount("BTC", "1.0")
529 trade
= portfolioTrade(value_from
, value_to
, "ETH")
530 self
.assertEqual("BTC", trade
.base_currency
)
531 self
.assertEqual("ETH", trade
.currency
)
533 with self
.assertRaises(AssertionError):
534 portfolio
.Trade(value_from
, value_to
, "ETC")
535 with self
.assertRaises(AssertionError):
536 value_from
.linked_to
= None
537 portfolio
.Trade(value_from
, value_to
, "ETH")
538 with self
.assertRaises(AssertionError):
539 value_from
.currency
= "ETH"
540 portfolio
.Trade(value_from
, value_to
, "ETH")
542 @unittest.skip("TODO")
543 def test_fetch_fees(self
):
546 @unittest.skip("TODO")
547 def test_compute_trades(self
):
550 @unittest.skip("TODO")
551 def test_action(self
):
554 @unittest.skip("TODO")
555 def test_action(self
):
558 @unittest.skip("TODO")
559 def test_order_action(self
):
562 @unittest.skip("TODO")
563 def test_prepare_order(self
):
566 @unittest.skip("TODO")
567 def test_all_orders(self
):
570 @unittest.skip("TODO")
571 def test_follow_orders(self
):
574 @unittest.skip("TODO")
575 def test_compute_value(self
):
578 @unittest.skip("TODO")
579 def test__repr(self
):
585 class AcceptanceTest(unittest
.TestCase
):
589 super(AcceptanceTest
, self
).setUp()
592 mock
.patch
.multiple(portfolio
.Balance
, known_balances
={}),
593 mock
.patch
.multiple(portfolio
.Portfolio
, data
=None, liquidities
={}),
594 mock
.patch
.multiple(portfolio
.Trade
,
596 ticker_cache_timestamp
=self
.time
.time(),
599 mock
.patch
.multiple(portfolio
.Computation
,
600 computations
=portfolio
.Computation
.computations
)
602 for patcher
in self
.patchers
:
605 def test_success_sell_only_necessary(self
):
620 "total": D("1000.0"),
624 "ETH": (D("0.25"), "long"),
625 "ETC": (D("0.25"), "long"),
626 "BTC": (D("0.4"), "long"),
627 "BTD": (D("0.01"), "short"),
628 "B2X": (D("0.04"), "long"),
629 "USDT": (D("0.05"), "long"),
632 def fetch_ticker(symbol
):
633 if symbol
== "ETH/BTC":
639 if symbol
== "ETC/BTC":
645 if symbol
== "XVG/BTC":
651 if symbol
== "BTD/BTC":
657 if symbol
== "B2X/BTC":
663 if symbol
== "USDT/BTC":
664 raise portfolio
.ExchangeError
665 if symbol
== "BTC/USDT":
667 "symbol": "BTC/USDT",
671 self
.fail("Shouldn't have been called with {}".format(symbol
))
674 market
.fetch_balance
.return_value
= fetch_balance
675 market
.fetch_ticker
.side_effect
= fetch_ticker
676 with mock
.patch
.object(portfolio
.Portfolio
, "repartition", return_value
=repartition
):
678 portfolio
.Balance
.prepare_trades(market
)
680 balances
= portfolio
.Balance
.known_balances
681 self
.assertEqual(portfolio
.Amount("ETH", 1), balances
["ETH"].total
)
682 self
.assertEqual(portfolio
.Amount("ETC", 4), balances
["ETC"].total
)
683 self
.assertEqual(portfolio
.Amount("XVG", 1000), balances
["XVG"].total
)
686 trades
= portfolio
.Trade
.trades
687 self
.assertEqual(portfolio
.Amount("BTC", D("0.15")), trades
["ETH"].value_from
)
688 self
.assertEqual(portfolio
.Amount("BTC", D("0.05")), trades
["ETH"].value_to
)
689 self
.assertEqual("sell", trades
["ETH"].action
)
691 self
.assertEqual(portfolio
.Amount("BTC", D("0.01")), trades
["ETC"].value_from
)
692 self
.assertEqual(portfolio
.Amount("BTC", D("0.05")), trades
["ETC"].value_to
)
693 self
.assertEqual("buy", trades
["ETC"].action
)
695 self
.assertNotIn("BTC", trades
)
697 self
.assertEqual(portfolio
.Amount("BTC", D("0.00")), trades
["BTD"].value_from
)
698 self
.assertEqual(portfolio
.Amount("BTC", D("0.002")), trades
["BTD"].value_to
)
699 self
.assertEqual("buy", trades
["BTD"].action
)
701 self
.assertEqual(portfolio
.Amount("BTC", D("0.00")), trades
["B2X"].value_from
)
702 self
.assertEqual(portfolio
.Amount("BTC", D("0.008")), trades
["B2X"].value_to
)
703 self
.assertEqual("buy", trades
["B2X"].action
)
705 self
.assertEqual(portfolio
.Amount("BTC", D("0.00")), trades
["USDT"].value_from
)
706 self
.assertEqual(portfolio
.Amount("BTC", D("0.01")), trades
["USDT"].value_to
)
707 self
.assertEqual("buy", trades
["USDT"].action
)
709 self
.assertEqual(portfolio
.Amount("BTC", D("0.04")), trades
["XVG"].value_from
)
710 self
.assertEqual(portfolio
.Amount("BTC", D("0.00")), trades
["XVG"].value_to
)
711 self
.assertEqual("sell", trades
["XVG"].action
)
714 portfolio
.Trade
.prepare_orders(only
="sell", compute_value
=lambda x
, y
: x
["bid"] * D("1.001"))
716 all_orders
= portfolio
.Trade
.all_orders()
717 self
.assertEqual(2, len(all_orders
))
718 self
.assertEqual(2, 3*all_orders
[0].amount
.value
)
719 self
.assertEqual(D("0.14014"), all_orders
[0].rate
)
720 self
.assertEqual(1000, all_orders
[1].amount
.value
)
721 self
.assertEqual(D("0.00003003"), all_orders
[1].rate
)
724 def create_order(symbol
, type, action
, amount
, price
=None, account
="exchange"):
725 self
.assertEqual("limit", type)
726 if symbol
== "ETH/BTC":
727 self
.assertEqual("sell", action
)
728 self
.assertEqual(D('0.66666666'), amount
)
729 self
.assertEqual(D("0.14014"), price
)
730 elif symbol
== "XVG/BTC":
731 self
.assertEqual("sell", action
)
732 self
.assertEqual(1000, amount
)
733 self
.assertEqual(D("0.00003003"), price
)
735 self
.fail("I shouldn't have been called")
740 market
.create_order
.side_effect
= create_order
741 market
.order_precision
.return_value
= 8
744 portfolio
.Trade
.run_orders()
746 self
.assertEqual("open", all_orders
[0].status
)
747 self
.assertEqual("open", all_orders
[1].status
)
749 market
.fetch_order
.return_value
= { "status": "closed" }
750 with mock
.patch
.object(portfolio
.time
, "sleep") as sleep
:
752 portfolio
.Trade
.follow_orders(verbose
=False)
754 sleep
.assert_called_with(30)
756 for order
in all_orders
:
757 self
.assertEqual("closed", order
.status
)
761 "free": D("1.0") / 3,
763 "total": D("1.0") / 3,
781 market
.fetch_balance
.return_value
= fetch_balance
783 with mock
.patch
.object(portfolio
.Portfolio
, "repartition", return_value
=repartition
):
785 portfolio
.Balance
.update_trades(market
, only
="buy", compute_value
="average")
787 balances
= portfolio
.Balance
.known_balances
788 self
.assertEqual(portfolio
.Amount("ETH", 1 / D("3")), balances
["ETH"].total
)
789 self
.assertEqual(portfolio
.Amount("ETC", 4), balances
["ETC"].total
)
790 self
.assertEqual(portfolio
.Amount("BTC", D("0.134")), balances
["BTC"].total
)
791 self
.assertEqual(portfolio
.Amount("XVG", 0), balances
["XVG"].total
)
794 trades
= portfolio
.Trade
.trades
795 self
.assertEqual(portfolio
.Amount("BTC", D("0.15")), trades
["ETH"].value_from
)
796 self
.assertEqual(portfolio
.Amount("BTC", D("0.05")), trades
["ETH"].value_to
)
797 self
.assertEqual("sell", trades
["ETH"].action
)
799 self
.assertEqual(portfolio
.Amount("BTC", D("0.01")), trades
["ETC"].value_from
)
800 self
.assertEqual(portfolio
.Amount("BTC", D("0.0485")), trades
["ETC"].value_to
)
801 self
.assertEqual("buy", trades
["ETC"].action
)
803 self
.assertNotIn("BTC", trades
)
805 self
.assertEqual(portfolio
.Amount("BTC", D("0.00")), trades
["BTD"].value_from
)
806 self
.assertEqual(portfolio
.Amount("BTC", D("0.00194")), trades
["BTD"].value_to
)
807 self
.assertEqual("buy", trades
["BTD"].action
)
809 self
.assertEqual(portfolio
.Amount("BTC", D("0.00")), trades
["B2X"].value_from
)
810 self
.assertEqual(portfolio
.Amount("BTC", D("0.00776")), trades
["B2X"].value_to
)
811 self
.assertEqual("buy", trades
["B2X"].action
)
813 self
.assertEqual(portfolio
.Amount("BTC", D("0.00")), trades
["USDT"].value_from
)
814 self
.assertEqual(portfolio
.Amount("BTC", D("0.0097")), trades
["USDT"].value_to
)
815 self
.assertEqual("buy", trades
["USDT"].action
)
817 self
.assertEqual(portfolio
.Amount("BTC", D("0.04")), trades
["XVG"].value_from
)
818 self
.assertEqual(portfolio
.Amount("BTC", D("0.00")), trades
["XVG"].value_to
)
819 self
.assertEqual("sell", trades
["XVG"].action
)
822 portfolio
.Trade
.prepare_orders(only
="buy", compute_value
=lambda x
, y
: x
["ask"])
824 all_orders
= portfolio
.Trade
.all_orders(state
="pending")
825 self
.assertEqual(4, len(all_orders
))
826 self
.assertEqual(portfolio
.Amount("ETC", D("12.83333333")), round(all_orders
[0].amount
))
827 self
.assertEqual(D("0.003"), all_orders
[0].rate
)
828 self
.assertEqual("buy", all_orders
[0].action
)
829 self
.assertEqual("long", all_orders
[0].trade_type
)
831 self
.assertEqual(portfolio
.Amount("BTD", D("1.61666666")), round(all_orders
[1].amount
))
832 self
.assertEqual(D("0.0012"), all_orders
[1].rate
)
833 self
.assertEqual("sell", all_orders
[1].action
)
834 self
.assertEqual("short", all_orders
[1].trade_type
)
836 diff
= portfolio
.Amount("B2X", D("19.4")/3) - all_orders
[2].amount
837 self
.assertAlmostEqual(0, diff
.value
)
838 self
.assertEqual(D("0.0012"), all_orders
[2].rate
)
839 self
.assertEqual("buy", all_orders
[2].action
)
840 self
.assertEqual("long", all_orders
[2].trade_type
)
842 self
.assertEqual(portfolio
.Amount("BTC", D("0.0097")), all_orders
[3].amount
)
843 self
.assertEqual(D("16000"), all_orders
[3].rate
)
844 self
.assertEqual("sell", all_orders
[3].action
)
845 self
.assertEqual("long", all_orders
[3].trade_type
)
849 # portfolio.Trade.run_orders()
851 with mock
.patch
.object(portfolio
.time
, "sleep") as sleep
:
853 portfolio
.Trade
.follow_orders(verbose
=False)
855 sleep
.assert_called_with(30)
858 for patcher
in self
.patchers
:
861 if __name__
== '__main__':