3 from unittest
import mock
5 class AmountTest(unittest
.TestCase
):
7 amount
= portfolio
.Amount("BTC", 0.65)
8 self
.assertEqual(0.65, amount
.value
)
9 self
.assertEqual("BTC", amount
.currency
)
11 amount
= portfolio
.Amount("BTC", 10, int_val
=2000000000000000)
12 self
.assertEqual(0.002, amount
.value
)
14 def test_in_currency(self
):
15 amount
= portfolio
.Amount("ETC", 10)
17 self
.assertEqual(amount
, amount
.in_currency("ETC", None))
19 ticker_mock
= unittest
.mock
.Mock()
20 with mock
.patch
.object(portfolio
.Amount
, 'get_ticker', new
=ticker_mock
):
21 ticker_mock
.return_value
= None
22 portfolio
.Amount
.get_ticker
= ticker_mock
24 self
.assertRaises(Exception, amount
.in_currency
, "ETH", None)
26 with mock
.patch
.object(portfolio
.Amount
, 'get_ticker', new
=ticker_mock
):
27 ticker_mock
.return_value
= {
31 converted_amount
= amount
.in_currency("ETH", None)
33 self
.assertEqual(3.0, converted_amount
.value
)
34 self
.assertEqual("ETH", converted_amount
.currency
)
35 self
.assertEqual(amount
, converted_amount
.linked_to
)
36 self
.assertEqual("bar", converted_amount
.ticker
["foo"])
38 @unittest.skip("TODO")
39 def test_get_ticker(self
):
43 amount
= portfolio
.Amount("SC", -120)
44 self
.assertEqual(120, abs(amount
).value
)
45 self
.assertEqual("SC", abs(amount
).currency
)
47 amount
= portfolio
.Amount("SC", 10)
48 self
.assertEqual(10, abs(amount
).value
)
49 self
.assertEqual("SC", abs(amount
).currency
)
52 amount1
= portfolio
.Amount("XVG", 12.9)
53 amount2
= portfolio
.Amount("XVG", 13.1)
55 self
.assertEqual(26, (amount1
+ amount2
).value
)
56 self
.assertEqual("XVG", (amount1
+ amount2
).currency
)
58 amount3
= portfolio
.Amount("ETH", 1.6)
59 with self
.assertRaises(Exception):
62 amount4
= portfolio
.Amount("ETH", 0.0)
63 self
.assertEqual(amount1
, amount1
+ amount4
)
66 amount
= portfolio
.Amount("XVG", 12.9)
68 self
.assertEqual(amount
, 0 + amount
)
69 with self
.assertRaises(Exception):
73 amount1
= portfolio
.Amount("XVG", 13.3)
74 amount2
= portfolio
.Amount("XVG", 13.1)
76 self
.assertEqual(0.2, (amount1
- amount2
).value
)
77 self
.assertEqual("XVG", (amount1
- amount2
).currency
)
79 amount3
= portfolio
.Amount("ETH", 1.6)
80 with self
.assertRaises(Exception):
83 amount4
= portfolio
.Amount("ETH", 0.0)
84 self
.assertEqual(amount1
, amount1
- amount4
)
87 amount
= portfolio
.Amount("XMR", 0.1)
88 self
.assertEqual(100000000000000000, int(amount
))
91 amount
= portfolio
.Amount("XEM", 11)
93 self
.assertEqual(38.5, (amount
* 3.5).value
)
94 self
.assertEqual(33, (amount
* 3).value
)
96 with self
.assertRaises(Exception):
100 amount
= portfolio
.Amount("XEM", 11)
102 self
.assertEqual(38.5, (3.5 * amount
).value
)
103 self
.assertEqual(33, (3 * amount
).value
)
105 def test__floordiv(self
):
106 amount
= portfolio
.Amount("XEM", 11)
108 self
.assertEqual(5.5, (amount
// 2).value
)
109 with self
.assertRaises(TypeError):
111 self
.assertEqual(1571428571428571428, (amount
// 7)._value
)
114 amount
= portfolio
.Amount("XEM", 11)
116 with self
.assertRaises(TypeError):
118 self
.assertEqual(5.5, (amount
/ 2).value
)
119 self
.assertEqual(1571428571428571428, (amount
/ 7)._value
)
122 amount1
= portfolio
.Amount("BTD", 11.3)
123 amount2
= portfolio
.Amount("BTD", 13.1)
125 self
.assertTrue(amount1
< amount2
)
126 self
.assertFalse(amount2
< amount1
)
127 self
.assertFalse(amount1
< amount1
)
129 amount3
= portfolio
.Amount("BTC", 1.6)
130 with self
.assertRaises(Exception):
134 amount1
= portfolio
.Amount("BTD", 11.3)
135 amount2
= portfolio
.Amount("BTD", 13.1)
136 amount3
= portfolio
.Amount("BTD", 11.3)
138 self
.assertFalse(amount1
== amount2
)
139 self
.assertFalse(amount2
== amount1
)
140 self
.assertTrue(amount1
== amount3
)
141 self
.assertFalse(amount2
== 0)
143 amount4
= portfolio
.Amount("BTC", 1.6)
144 with self
.assertRaises(Exception):
147 amount5
= portfolio
.Amount("BTD", 0)
148 self
.assertTrue(amount5
== 0)
151 amount1
= portfolio
.Amount("BTX", 32)
152 self
.assertEqual("32.00000000 BTX", str(amount1
))
154 amount2
= portfolio
.Amount("USDT", 12000)
155 amount1
.linked_to
= amount2
156 self
.assertEqual("32.00000000 BTX [12000.00000000 USDT]", str(amount1
))
158 def test__repr(self
):
159 amount1
= portfolio
.Amount("BTX", 32)
160 self
.assertEqual("Amount(32.00000000 BTX)", repr(amount1
))
162 amount2
= portfolio
.Amount("USDT", 12000)
163 amount1
.linked_to
= amount2
164 self
.assertEqual("Amount(32.00000000 BTX -> Amount(12000.00000000 USDT))", repr(amount1
))
166 amount3
= portfolio
.Amount("BTC", 0.1)
167 amount2
.linked_to
= amount3
168 self
.assertEqual("Amount(32.00000000 BTX -> Amount(12000.00000000 USDT -> Amount(0.10000000 BTC)))", repr(amount1
))
170 class PortfolioTest(unittest
.TestCase
):
173 if self
.json_response
is not None:
174 portfolio
.Portfolio
.data
= self
.json_response
177 super(PortfolioTest
, self
).setUp()
179 with open("test_portfolio.json") as example
:
181 self
.json_response
= json
.load(example
)
183 self
.patcher
= mock
.patch
.multiple(portfolio
.Portfolio
, data
=None, liquidities
={})
186 @mock.patch.object(urllib3
, "disable_warnings")
187 @mock.patch.object(urllib3
.poolmanager
.PoolManager
, "request")
188 @mock.patch.object(portfolio
.Portfolio
, "URL", new
="foo://bar")
189 def test_get_cryptoportfolio(self
, request
, disable_warnings
):
190 request
.side_effect
= [
191 type('', (), { "data": '{ "foo": "bar" }
' }),
192 type('', (), { "data": 'System Error' }),
193 Exception("Connection error"),
196 portfolio.Portfolio.get_cryptoportfolio()
197 self.assertIn("foo", portfolio.Portfolio.data)
198 self.assertEqual("bar", portfolio.Portfolio.data["foo"])
199 request.assert_called_with("GET", "foo://bar")
202 portfolio.Portfolio.get_cryptoportfolio()
203 self.assertIsNone(portfolio.Portfolio.data)
204 request.assert_called_with("GET", "foo://bar")
207 portfolio.Portfolio.data = "foo"
208 portfolio.Portfolio.get_cryptoportfolio()
209 request.assert_called_with("GET", "foo://bar")
210 self.assertEqual("foo", portfolio.Portfolio.data)
211 disable_warnings.assert_called_with()
213 @mock.patch.object(portfolio.Portfolio, "get_cryptoportfolio")
214 def test_parse_cryptoportfolio(self, mock_get):
215 mock_get.side_effect = self.fill_data
217 portfolio.Portfolio.parse_cryptoportfolio()
219 self.assertListEqual(
221 list(portfolio.Portfolio.liquidities.keys()))
223 liquidities = portfolio.Portfolio.liquidities
224 self.assertEqual(10, len(liquidities["medium"].keys()))
225 self.assertEqual(10, len(liquidities["high"].keys()))
227 expected = {'BTC': 2857, 'DGB': 1015, 'DOGE': 1805, 'SC': 623, 'ZEC': 3701}
228 self.assertDictEqual(expected, liquidities["high"]['2018-01-08'])
230 expected = {'ETC': 1000, 'FCT': 1000, 'GAS': 1000, 'NAV': 1000, 'OMG': 1000, 'OMNI': 1000, 'PPC': 1000, 'RIC': 1000, 'VIA': 1000, 'XCP': 1000}
231 self.assertDictEqual(expected, liquidities["medium"]['2018-01-08'])
233 # It doesn't refetch the data when available
234 portfolio
.Portfolio
.parse_cryptoportfolio()
235 mock_get
.assert_called_once_with()
237 portfolio
.Portfolio
.data
["portfolio_1"]["holding"]["direction"][3] = "short"
238 self
.assertRaises(AssertionError, portfolio
.Portfolio
.parse_cryptoportfolio
)
240 @mock.patch.object(portfolio
.Portfolio
, "get_cryptoportfolio")
241 def test_repartition_pertenthousand(self
, mock_get
):
242 mock_get
.side_effect
= self
.fill_data
244 expected_medium
= {'USDT': 1000, 'ETC': 1000, 'FCT': 1000, 'OMG': 1000, 'STEEM': 1000, 'STRAT': 1000, 'XEM': 1000, 'XMR': 1000, 'XVC': 1000, 'ZRX': 1000}
245 expected_high
= {'USDT': 1226, 'BTC': 1429, 'ETC': 1127, 'ETH': 1569, 'FCT': 3341, 'GAS': 1308}
247 self
.assertEqual(expected_medium
, portfolio
.Portfolio
.repartition_pertenthousand())
248 self
.assertEqual(expected_medium
, portfolio
.Portfolio
.repartition_pertenthousand(liquidity
="medium"))
249 self
.assertEqual(expected_high
, portfolio
.Portfolio
.repartition_pertenthousand(liquidity
="high"))
254 class BalanceTest(unittest
.TestCase
):
256 super(BalanceTest
, self
).setUp()
258 self
.fetch_balance
= {
279 self
.patcher
= mock
.patch
.multiple(portfolio
.Balance
, known_balances
={}, trades={}
)
282 def test_values(self
):
283 balance
= portfolio
.Balance("BTC", 0.65, 0.35, 0.30)
284 self
.assertEqual(0.65, balance
.total
.value
)
285 self
.assertEqual(0.35, balance
.free
.value
)
286 self
.assertEqual(0.30, balance
.used
.value
)
287 self
.assertEqual("BTC", balance
.currency
)
289 balance
= portfolio
.Balance
.from_hash("BTC", { "total": 0.65, "free": 0.35, "used": 0.30}
)
290 self
.assertEqual(0.65, balance
.total
.value
)
291 self
.assertEqual(0.35, balance
.free
.value
)
292 self
.assertEqual(0.30, balance
.used
.value
)
293 self
.assertEqual("BTC", balance
.currency
)
295 @mock.patch.object(portfolio
.Amount
, "get_ticker")
296 def test_in_currency(self
, get_ticker
):
297 portfolio
.Balance
.known_balances
= {
298 "BTC": portfolio
.Balance("BTC", 0.65, 0.35, 0.30),
299 "ETH": portfolio
.Balance("ETH", 3, 3, 0),
302 get_ticker
.return_value
= {
308 amounts
= portfolio
.Balance
.in_currency("BTC", market
)
309 self
.assertEqual("BTC", amounts
["ETH"].currency
)
310 self
.assertEqual(0.65, amounts
["BTC"].value
)
311 self
.assertEqual(0.30, amounts
["ETH"].value
)
313 amounts
= portfolio
.Balance
.in_currency("BTC", market
, action
="bid")
314 self
.assertEqual(0.65, amounts
["BTC"].value
)
315 self
.assertEqual(0.27, amounts
["ETH"].value
)
317 amounts
= portfolio
.Balance
.in_currency("BTC", market
, action
="bid", type="used")
318 self
.assertEqual(0.30, amounts
["BTC"].value
)
319 self
.assertEqual(0, amounts
["ETH"].value
)
321 def test_currencies(self
):
322 portfolio
.Balance
.known_balances
= {
323 "BTC": portfolio
.Balance("BTC", 0.65, 0.35, 0.30),
324 "ETH": portfolio
.Balance("ETH", 3, 3, 0),
326 self
.assertListEqual(["BTC", "ETH"], list(portfolio
.Balance
.currencies()))
328 @mock.patch.object(portfolio
.market
, "fetch_balance")
329 def test_fetch_balances(self
, fetch_balance
):
330 fetch_balance
.return_value
= self
.fetch_balance
332 portfolio
.Balance
.fetch_balances(portfolio
.market
)
333 self
.assertNotIn("XMR", portfolio
.Balance
.currencies())
334 self
.assertEqual(["USDT", "XVG"], list(portfolio
.Balance
.currencies()))
336 @mock.patch.object(portfolio
.Portfolio
, "repartition_pertenthousand")
337 @mock.patch.object(portfolio
.market
, "fetch_balance")
338 def test_dispatch_assets(self
, fetch_balance
, repartition
):
339 fetch_balance
.return_value
= self
.fetch_balance
340 portfolio
.Balance
.fetch_balances(portfolio
.market
)
342 self
.assertNotIn("XEM", portfolio
.Balance
.currencies())
344 repartition
.return_value
= {
349 amounts
= portfolio
.Balance
.dispatch_assets(portfolio
.Amount("BTC", 10.1))
350 self
.assertIn("XEM", portfolio
.Balance
.currencies())
351 self
.assertEqual(2.6, amounts
["BTC"].value
)
352 self
.assertEqual(7.5, amounts
["XEM"].value
)
354 @mock.patch.object(portfolio
.Portfolio
, "repartition_pertenthousand")
355 @mock.patch.object(portfolio
.Amount
, "get_ticker")
356 @mock.patch.object(portfolio
.Trade
, "compute_trades")
357 def test_prepare_trades(self
, compute_trades
, get_ticker
, repartition
):
358 repartition
.return_value
= {
362 get_ticker
.side_effect
= [
363 { "average": 0.0001 }
,
364 { "average": 0.000001 }
367 market
.fetch_balance
.return_value
= {
379 portfolio
.Balance
.prepare_trades(market
)
380 compute_trades
.assert_called()
382 call
= compute_trades
.call_args
383 self
.assertEqual(market
, call
[1]["market"])
384 self
.assertEqual(1, call
[0][0]["USDT"].value
)
385 self
.assertEqual(0.01, call
[0][0]["XVG"].value
)
386 self
.assertEqual(0.2525, call
[0][1]["BTC"].value
)
387 self
.assertEqual(0.7575, call
[0][1]["XEM"].value
)
389 def test__repr(self
):
390 balance
= portfolio
.Balance("BTX", 3, 1, 2)
391 self
.assertEqual("Balance(BTX [1.00000000 BTX/2.00000000 BTX/3.00000000 BTX])", repr(balance
))
396 if __name__
== '__main__':