+ expected = {
+ "info": {
+ "exchange": {
+ "BLK": "159.83673869",
+ "BTC": "0.00005959",
+ "USDT": "0.00002625",
+ "XMR": "0.18719303"
+ },
+ "margin": {
+ "BTC": "0.03019227"
+ }
+ },
+ "exchange": {
+ "BLK": D("159.83673869"),
+ "BTC": D("0.00005959"),
+ "USDT": D("0.00002625"),
+ "XMR": D("0.18719303")
+ },
+ "margin": {"BTC": D("0.03019227")},
+ "BLK": {"exchange": D("159.83673869")},
+ "BTC": {"exchange": D("0.00005959"), "margin": D("0.03019227")},
+ "USDT": {"exchange": D("0.00002625")},
+ "XMR": {"exchange": D("0.18719303")}
+ }
+ result = self.s.fetch_balance_per_type()
+ self.assertEqual(expected, result)
+
+ def test_fetch_all_balances(self):
+ import json
+ with mock.patch.object(self.s, "load_markets") as load_markets,\
+ mock.patch.object(self.s, "privatePostGetMarginPosition") as margin_balance,\
+ mock.patch.object(self.s, "privatePostReturnCompleteBalances") as balance,\
+ mock.patch.object(self.s, "privatePostReturnAvailableAccountBalances") as balance_per_type:
+
+ with open("test_samples/poloniexETest.test_fetch_all_balances.1.json") as f:
+ balance.return_value = json.load(f)
+ with open("test_samples/poloniexETest.test_fetch_all_balances.2.json") as f:
+ margin_balance.return_value = json.load(f)
+ with open("test_samples/poloniexETest.test_fetch_all_balances.3.json") as f:
+ balance_per_type.return_value = json.load(f)
+
+ result = self.s.fetch_all_balances()
+ expected_doge = {
+ "total": D("-12779.79821852"),
+ "exchange_used": D("0E-8"),
+ "exchange_total": D("0E-8"),
+ "exchange_free": D("0E-8"),
+ "margin_available": 0,
+ "margin_in_position": 0,
+ "margin_borrowed": D("12779.79821852"),
+ "margin_total": D("-12779.79821852"),
+ "margin_pending_gain": 0,
+ "margin_lending_fees": D("-9E-8"),
+ "margin_pending_base_gain": D("0.00024059"),
+ "margin_position_type": "short",
+ "margin_liquidation_price": D("0.00000246"),
+ "margin_borrowed_base_price": D("0.00599149"),
+ "margin_borrowed_base_currency": "BTC"
+ }
+ expected_btc = {"total": D("0.05432165"),
+ "exchange_used": D("0E-8"),
+ "exchange_total": D("0.00005959"),
+ "exchange_free": D("0.00005959"),
+ "margin_available": D("0.03019227"),
+ "margin_in_position": D("0.02406979"),
+ "margin_borrowed": 0,
+ "margin_total": D("0.05426206"),
+ "margin_pending_gain": D("0.00093955"),
+ "margin_lending_fees": 0,
+ "margin_pending_base_gain": 0,
+ "margin_position_type": None,
+ "margin_liquidation_price": 0,
+ "margin_borrowed_base_price": 0,
+ "margin_borrowed_base_currency": None
+ }
+ expected_xmr = {"total": D("0.18719303"),
+ "exchange_used": D("0E-8"),
+ "exchange_total": D("0.18719303"),
+ "exchange_free": D("0.18719303"),
+ "margin_available": 0,
+ "margin_in_position": 0,
+ "margin_borrowed": 0,
+ "margin_total": 0,
+ "margin_pending_gain": 0,
+ "margin_lending_fees": 0,
+ "margin_pending_base_gain": 0,
+ "margin_position_type": None,
+ "margin_liquidation_price": 0,
+ "margin_borrowed_base_price": 0,
+ "margin_borrowed_base_currency": None
+ }
+ self.assertEqual(expected_xmr, result["XMR"])
+ self.assertEqual(expected_doge, result["DOGE"])
+ self.assertEqual(expected_btc, result["BTC"])
+
+ def test_create_margin_order(self):
+ with self.assertRaises(market.ExchangeError):
+ self.s.create_margin_order("FOO", "market", "buy", "10")
+
+ with mock.patch.object(self.s, "load_markets") as load_markets,\
+ mock.patch.object(self.s, "privatePostMarginBuy") as margin_buy,\
+ mock.patch.object(self.s, "privatePostMarginSell") as margin_sell,\
+ mock.patch.object(self.s, "market") as market_mock,\
+ mock.patch.object(self.s, "price_to_precision") as ptp,\
+ mock.patch.object(self.s, "amount_to_precision") as atp:
+
+ margin_buy.return_value = {
+ "orderNumber": 123
+ }
+ margin_sell.return_value = {
+ "orderNumber": 456
+ }
+ market_mock.return_value = { "id": "BTC_ETC", "symbol": "BTC_ETC" }
+ ptp.return_value = D("0.1")
+ atp.return_value = D("12")
+
+ order = self.s.create_margin_order("BTC_ETC", "margin", "buy", "12", price="0.1")
+ self.assertEqual(123, order["id"])
+ margin_buy.assert_called_once_with({"currencyPair": "BTC_ETC", "rate": D("0.1"), "amount": D("12")})
+ margin_sell.assert_not_called()
+ margin_buy.reset_mock()
+ margin_sell.reset_mock()
+
+ order = self.s.create_margin_order("BTC_ETC", "margin", "sell", "12", lending_rate="0.01", price="0.1")
+ self.assertEqual(456, order["id"])
+ margin_sell.assert_called_once_with({"currencyPair": "BTC_ETC", "rate": D("0.1"), "amount": D("12"), "lendingRate": "0.01"})
+ margin_buy.assert_not_called()
+
+ def test_create_exchange_order(self):
+ with mock.patch.object(market.ccxt.poloniex, "create_order") as create_order:
+ self.s.create_order("symbol", "type", "side", "amount", price="price", params="params")
+
+ create_order.assert_called_once_with("symbol", "type", "side", "amount", price="price", params="params")
+
+@unittest.skipUnless("unit" in limits, "Unit skipped")
+class NoopLockTest(unittest.TestCase):
+ def test_with(self):
+ noop_lock = store.NoopLock()
+ with noop_lock:
+ self.assertTrue(True)
+
+@unittest.skipUnless("unit" in limits, "Unit skipped")
+class LockedVar(unittest.TestCase):
+
+ def test_values(self):
+ locked_var = store.LockedVar("Foo")
+ self.assertIsInstance(locked_var.lock, store.NoopLock)
+ self.assertEqual("Foo", locked_var.val)
+
+ def test_get(self):
+ with self.subTest(desc="Normal case"):
+ locked_var = store.LockedVar("Foo")
+ self.assertEqual("Foo", locked_var.get())
+ with self.subTest(desc="Dict"):
+ locked_var = store.LockedVar({"foo": "bar"})
+ self.assertEqual({"foo": "bar"}, locked_var.get())
+ self.assertEqual("bar", locked_var.get("foo"))
+ self.assertIsNone(locked_var.get("other"))
+
+ def test_set(self):
+ locked_var = store.LockedVar("Foo")
+ locked_var.set("Bar")
+ self.assertEqual("Bar", locked_var.get())
+
+ def test__getattr(self):
+ dummy = type('Dummy', (object,), {})()
+ dummy.attribute = "Hey"
+
+ locked_var = store.LockedVar(dummy)
+ self.assertEqual("Hey", locked_var.attribute)
+ with self.assertRaises(AttributeError):
+ locked_var.other
+
+ def test_start_lock(self):
+ locked_var = store.LockedVar("Foo")
+ locked_var.start_lock()
+ self.assertEqual("lock", locked_var.lock.__class__.__name__)
+
+ thread1 = threading.Thread(target=locked_var.set, args=["Bar1"])
+ thread2 = threading.Thread(target=locked_var.set, args=["Bar2"])
+ thread3 = threading.Thread(target=locked_var.set, args=["Bar3"])
+
+ with locked_var.lock:
+ thread1.start()
+ thread2.start()
+ thread3.start()
+
+ self.assertEqual("Foo", locked_var.val)
+ thread1.join()
+ thread2.join()
+ thread3.join()
+ self.assertEqual("Bar", locked_var.get()[0:3])
+
+ def test_wait_for_notification(self):
+ with self.assertRaises(RuntimeError):
+ store.Portfolio.wait_for_notification()
+
+ with mock.patch.object(store.Portfolio, "get_cryptoportfolio") as get,\
+ mock.patch.object(store.Portfolio, "report") as report,\
+ mock.patch.object(store.time, "sleep") as sleep:
+ store.Portfolio.start_worker(poll=3)
+
+ store.Portfolio.worker_notify.set()
+
+ store.Portfolio.callback.wait()
+
+ report.print_log.assert_called_once_with("Fetching cryptoportfolio")
+ get.assert_called_once_with(refetch=True)
+ sleep.assert_called_once_with(3)
+ self.assertFalse(store.Portfolio.worker_notify.is_set())
+ self.assertTrue(store.Portfolio.worker.is_alive())
+
+ store.Portfolio.callback.clear()
+ store.Portfolio.worker_started = False
+ store.Portfolio.worker_notify.set()
+ store.Portfolio.callback.wait()
+
+ self.assertFalse(store.Portfolio.worker.is_alive())
+
+ def test_notify_and_wait(self):
+ with mock.patch.object(store.Portfolio, "callback") as callback,\
+ mock.patch.object(store.Portfolio, "worker_notify") as worker_notify:
+ store.Portfolio.notify_and_wait()
+ callback.clear.assert_called_once_with()
+ worker_notify.set.assert_called_once_with()
+ callback.wait.assert_called_once_with()
+
+@unittest.skipUnless("unit" in limits, "Unit skipped")
+class PortfolioTest(WebMockTestCase):
+ def setUp(self):
+ super(PortfolioTest, self).setUp()