1 from .helper
import limits
, unittest
, mock
, D
5 @unittest.skipUnless("unit" in limits
, "Unit skipped")
6 class poloniexETest(unittest
.TestCase
):
9 self
.wm
= requests_mock
.Mocker()
12 self
.s
= market
.ccxt
.poloniexE()
19 with self
.subTest("Nominal case"), \
20 mock
.patch("market.ccxt.poloniexE.session") as session
:
21 session
.request
.return_value
= "response"
22 ccxt
= market
.ccxt
.poloniexE()
23 ccxt
._market
= mock
.Mock
24 ccxt
._market
.report
= mock
.Mock()
26 ccxt
.session
.request("GET", "URL", data
="data",
28 ccxt
._market
.report
.log_http_request
.assert_called_with('GET', 'URL', 'data',
29 'headers', 'response')
31 with self
.subTest("Raising"),\
32 mock
.patch("market.ccxt.poloniexE.session") as session
:
33 session
.request
.side_effect
= market
.ccxt
.RequestException("Boo")
35 ccxt
= market
.ccxt
.poloniexE()
36 ccxt
._market
= mock
.Mock
37 ccxt
._market
.report
= mock
.Mock()
39 with self
.assertRaises(market
.ccxt
.RequestException
, msg
="Boo") as cm
:
40 ccxt
.session
.request("GET", "URL", data
="data",
42 ccxt
._market
.report
.log_http_request
.assert_called_with('GET', 'URL', 'data',
43 'headers', cm
.exception
)
46 def test_nanoseconds(self
):
47 with mock
.patch
.object(market
.ccxt
.time
, "time") as time
:
48 time
.return_value
= 123456.7890123456
49 self
.assertEqual(123456789012345, self
.s
.nanoseconds())
52 with mock
.patch
.object(market
.ccxt
.time
, "time") as time
:
53 time
.return_value
= 123456.7890123456
54 self
.assertEqual(123456789012345, self
.s
.nonce())
56 def test_request(self
):
57 with mock
.patch
.object(market
.ccxt
.poloniex
, "request") as request
,\
58 mock
.patch("market.ccxt.retry_call") as retry_call
:
59 with self
.subTest(wrapped
=True):
60 with self
.subTest(desc
="public"):
62 retry_call
.assert_called_with(request
,
63 delay
=1, tries
=10, fargs
=["foo"],
64 fkwargs
={'api': 'public', 'method': 'GET', 'params': {}
, 'headers': None, 'body': None},
65 exceptions
=(market
.ccxt
.RequestTimeout
, market
.ccxt
.InvalidNonce
))
66 request
.assert_not_called()
68 with self
.subTest(desc
="private GET"):
69 self
.s
.request("foo", api
="private")
70 retry_call
.assert_called_with(request
,
71 delay
=1, tries
=10, fargs
=["foo"],
72 fkwargs
={'api': 'private', 'method': 'GET', 'params': {}
, 'headers': None, 'body': None},
73 exceptions
=(market
.ccxt
.RequestTimeout
, market
.ccxt
.InvalidNonce
))
74 request
.assert_not_called()
76 with self
.subTest(desc
="private POST regexp"):
77 self
.s
.request("returnFoo", api
="private", method
="POST")
78 retry_call
.assert_called_with(request
,
79 delay
=1, tries
=10, fargs
=["returnFoo"],
80 fkwargs
={'api': 'private', 'method': 'POST', 'params': {}
, 'headers': None, 'body': None},
81 exceptions
=(market
.ccxt
.RequestTimeout
, market
.ccxt
.InvalidNonce
))
82 request
.assert_not_called()
84 with self
.subTest(desc
="private POST non-regexp"):
85 self
.s
.request("getMarginPosition", api
="private", method
="POST")
86 retry_call
.assert_called_with(request
,
87 delay
=1, tries
=10, fargs
=["getMarginPosition"],
88 fkwargs
={'api': 'private', 'method': 'POST', 'params': {}
, 'headers': None, 'body': None},
89 exceptions
=(market
.ccxt
.RequestTimeout
, market
.ccxt
.InvalidNonce
))
90 request
.assert_not_called()
91 retry_call
.reset_mock()
93 with self
.subTest(wrapped
=False):
94 with self
.subTest(desc
="private POST non-matching regexp"):
95 self
.s
.request("marginBuy", api
="private", method
="POST")
96 request
.assert_called_with("marginBuy",
97 api
="private", method
="POST", params
={},
98 headers
=None, body
=None)
99 retry_call
.assert_not_called()
101 with self
.subTest(desc
="private POST non-matching non-regexp"):
102 self
.s
.request("closeMarginPositionOther", api
="private", method
="POST")
103 request
.assert_called_with("closeMarginPositionOther",
104 api
="private", method
="POST", params
={},
105 headers
=None, body
=None)
106 retry_call
.assert_not_called()
108 def test_order_precision(self
):
109 self
.assertEqual(8, self
.s
.order_precision("FOO"))
111 def test_transfer_balance(self
):
112 with self
.subTest(success
=True),\
113 mock
.patch
.object(self
.s
, "privatePostTransferBalance") as t
:
114 t
.return_value
= { "success": 1 }
115 result
= self
.s
.transfer_balance("FOO", 12, "exchange", "margin")
116 t
.assert_called_once_with({
119 "fromAccount": "exchange",
120 "toAccount": "margin",
123 self
.assertTrue(result
)
125 with self
.subTest(success
=False),\
126 mock
.patch
.object(self
.s
, "privatePostTransferBalance") as t
:
127 t
.return_value
= { "success": 0 }
128 self
.assertFalse(self
.s
.transfer_balance("FOO", 12, "exchange", "margin"))
130 def test_close_margin_position(self
):
131 with mock
.patch
.object(self
.s
, "privatePostCloseMarginPosition") as c
:
132 self
.s
.close_margin_position("FOO", "BAR")
133 c
.assert_called_with({"currencyPair": "BAR_FOO"}
)
135 def test_tradable_balances(self
):
136 with mock
.patch
.object(self
.s
, "privatePostReturnTradableBalances") as r
:
138 "FOO": { "exchange": "12.1234", "margin": "0.0123" }
,
139 "BAR": { "exchange": "1", "margin": "0" }
,
141 balances
= self
.s
.tradable_balances()
142 self
.assertEqual(["FOO", "BAR"], list(balances
.keys()))
143 self
.assertEqual(["exchange", "margin"], list(balances
["FOO"].keys()))
144 self
.assertEqual(D("12.1234"), balances
["FOO"]["exchange"])
145 self
.assertEqual(["exchange", "margin"], list(balances
["BAR"].keys()))
147 def test_margin_summary(self
):
148 with mock
.patch
.object(self
.s
, "privatePostReturnMarginAccountSummary") as r
:
150 "currentMargin": "1.49680968",
151 "lendingFees": "0.0000001",
153 "totalBorrowedValue": "0.00673602",
154 "totalValue": "0.01000000",
155 "netValue": "0.01008254",
158 'current_margin': D('1.49680968'),
159 'gains': D('0.00008254'),
160 'lending_fees': D('0.0000001'),
161 'total': D('0.01000000'),
162 'total_borrowed': D('0.00673602')
164 self
.assertEqual(expected
, self
.s
.margin_summary())
166 def test_create_order(self
):
167 with mock
.patch
.object(self
.s
, "create_exchange_order") as exchange
,\
168 mock
.patch
.object(self
.s
, "create_margin_order") as margin
:
169 with self
.subTest(account
="unspecified"):
170 self
.s
.create_order("symbol", "type", "side", "amount", price
="price", lending_rate
="lending_rate", params
="params")
171 exchange
.assert_called_once_with("symbol", "type", "side", "amount", price
="price", params
="params")
172 margin
.assert_not_called()
173 exchange
.reset_mock()
176 with self
.subTest(account
="exchange"):
177 self
.s
.create_order("symbol", "type", "side", "amount", account
="exchange", price
="price", lending_rate
="lending_rate", params
="params")
178 exchange
.assert_called_once_with("symbol", "type", "side", "amount", price
="price", params
="params")
179 margin
.assert_not_called()
180 exchange
.reset_mock()
183 with self
.subTest(account
="margin"):
184 self
.s
.create_order("symbol", "type", "side", "amount", account
="margin", price
="price", lending_rate
="lending_rate", params
="params")
185 margin
.assert_called_once_with("symbol", "type", "side", "amount", lending_rate
="lending_rate", price
="price", params
="params")
186 exchange
.assert_not_called()
187 exchange
.reset_mock()
190 with self
.subTest(account
="unknown"), self
.assertRaises(NotImplementedError):
191 self
.s
.create_order("symbol", "type", "side", "amount", account
="unknown")
193 def test_parse_ticker(self
):
197 "highestBid": "10.5",
200 "percentChange": "0.1",
207 with mock
.patch
.object(self
.s
, "milliseconds") as ms
:
208 ms
.return_value
= 1520292715123
209 result
= self
.s
.parse_ticker(ticker
, market
)
213 "timestamp": 1520292715123,
214 "datetime": "2018-03-05T23:31:55.123Z",
227 "baseVolume": D("10"),
228 "quoteVolume": D("20"),
231 self
.assertEqual(expected
, result
)
233 def test_fetch_margin_balance(self
):
234 with mock
.patch
.object(self
.s
, "privatePostGetMarginPosition") as get_margin_position
:
235 get_margin_position
.return_value
= {
238 "basePrice": "0.06818560",
239 "lendingFees": "0.00000001",
240 "liquidationPrice": "0.15107132",
242 "total": "0.00681856",
248 "lendingFees": "0.00000001",
249 "liquidationPrice": "0.6",
258 "liquidationPrice": "-1",
264 balances
= self
.s
.fetch_margin_balance()
265 self
.assertEqual(2, len(balances
))
269 "borrowedPrice": D("0.06818560"),
270 "lendingFees": D("1E-8"),
271 "pl": D("-0.00000371"),
272 "liquidationPrice": D("0.15107132"),
274 "total": D("0.00681856"),
275 "baseCurrency": "BTC"
279 "borrowedPrice": D("0.1"),
280 "lendingFees": D("1E-8"),
281 "pl": D("0.00000371"),
282 "liquidationPrice": D("0.6"),
285 "baseCurrency": "BTC"
288 self
.assertEqual(expected
, balances
)
291 self
.assertEqual(D("1.1"), self
.s
.sum(D("1"), D("0.1")))
293 def test_fetch_balance(self
):
294 with mock
.patch
.object(self
.s
, "load_markets") as load_markets
,\
295 mock
.patch
.object(self
.s
, "privatePostReturnCompleteBalances") as balances
,\
296 mock
.patch
.object(self
.s
, "common_currency_code") as ccc
:
297 ccc
.side_effect
= ["ETH", "BTC", "DASH"]
298 balances
.return_value
= {
315 "ETH": {"available": "10", "onOrders": "1"}
,
316 "BTC": {"available": "1", "onOrders": "0"}
,
317 "DASH": {"available": "0", "onOrders": "3"}
319 "ETH": {"free": D("10"), "used": D("1"), "total": D("11")}
,
320 "BTC": {"free": D("1"), "used": D("0"), "total": D("1")}
,
321 "DASH": {"free": D("0"), "used": D("3"), "total": D("3")}
,
322 "free": {"ETH": D("10"), "BTC": D("1"), "DASH": D("0")}
,
323 "used": {"ETH": D("1"), "BTC": D("0"), "DASH": D("3")}
,
324 "total": {"ETH": D("11"), "BTC": D("1"), "DASH": D("3")}
326 result
= self
.s
.fetch_balance()
327 load_markets
.assert_called_once()
328 self
.assertEqual(expected
, result
)
330 def test_fetch_balance_per_type(self
):
331 with mock
.patch
.object(self
.s
, "privatePostReturnAvailableAccountBalances") as balances
:
332 balances
.return_value
= {
334 "BLK": "159.83673869",
336 "USDT": "0.00002625",
346 "BLK": "159.83673869",
348 "USDT": "0.00002625",
356 "BLK": D("159.83673869"),
357 "BTC": D("0.00005959"),
358 "USDT": D("0.00002625"),
359 "XMR": D("0.18719303")
361 "margin": {"BTC": D("0.03019227")}
,
362 "BLK": {"exchange": D("159.83673869")}
,
363 "BTC": {"exchange": D("0.00005959"), "margin": D("0.03019227")}
,
364 "USDT": {"exchange": D("0.00002625")}
,
365 "XMR": {"exchange": D("0.18719303")}
367 result
= self
.s
.fetch_balance_per_type()
368 self
.assertEqual(expected
, result
)
370 def test_fetch_all_balances(self
):
372 with mock
.patch
.object(self
.s
, "load_markets") as load_markets
,\
373 mock
.patch
.object(self
.s
, "privatePostGetMarginPosition") as margin_balance
,\
374 mock
.patch
.object(self
.s
, "privatePostReturnCompleteBalances") as balance
,\
375 mock
.patch
.object(self
.s
, "privatePostReturnAvailableAccountBalances") as balance_per_type
:
377 with open("test_samples/poloniexETest.test_fetch_all_balances.1.json") as f
:
378 balance
.return_value
= json
.load(f
)
379 with open("test_samples/poloniexETest.test_fetch_all_balances.2.json") as f
:
380 margin_balance
.return_value
= json
.load(f
)
381 with open("test_samples/poloniexETest.test_fetch_all_balances.3.json") as f
:
382 balance_per_type
.return_value
= json
.load(f
)
384 result
= self
.s
.fetch_all_balances()
386 "total": D("-12779.79821852"),
387 "exchange_used": D("0E-8"),
388 "exchange_total": D("0E-8"),
389 "exchange_free": D("0E-8"),
390 "margin_available": 0,
391 "margin_in_position": 0,
392 "margin_borrowed": D("12779.79821852"),
393 "margin_total": D("-12779.79821852"),
394 "margin_pending_gain": 0,
395 "margin_lending_fees": D("-9E-8"),
396 "margin_pending_base_gain": D("0.00024059"),
397 "margin_position_type": "short",
398 "margin_liquidation_price": D("0.00000246"),
399 "margin_borrowed_base_price": D("0.00599149"),
400 "margin_borrowed_base_currency": "BTC"
402 expected_btc
= {"total": D("0.05432165"),
403 "exchange_used": D("0E-8"),
404 "exchange_total": D("0.00005959"),
405 "exchange_free": D("0.00005959"),
406 "margin_available": D("0.03019227"),
407 "margin_in_position": D("0.02406979"),
408 "margin_borrowed": 0,
409 "margin_total": D("0.05426206"),
410 "margin_pending_gain": D("0.00093955"),
411 "margin_lending_fees": 0,
412 "margin_pending_base_gain": 0,
413 "margin_position_type": None,
414 "margin_liquidation_price": 0,
415 "margin_borrowed_base_price": 0,
416 "margin_borrowed_base_currency": None
418 expected_xmr
= {"total": D("0.18719303"),
419 "exchange_used": D("0E-8"),
420 "exchange_total": D("0.18719303"),
421 "exchange_free": D("0.18719303"),
422 "margin_available": 0,
423 "margin_in_position": 0,
424 "margin_borrowed": 0,
426 "margin_pending_gain": 0,
427 "margin_lending_fees": 0,
428 "margin_pending_base_gain": 0,
429 "margin_position_type": None,
430 "margin_liquidation_price": 0,
431 "margin_borrowed_base_price": 0,
432 "margin_borrowed_base_currency": None
434 self
.assertEqual(expected_xmr
, result
["XMR"])
435 self
.assertEqual(expected_doge
, result
["DOGE"])
436 self
.assertEqual(expected_btc
, result
["BTC"])
438 def test_create_margin_order(self
):
439 with self
.assertRaises(market
.ExchangeError
):
440 self
.s
.create_margin_order("FOO", "market", "buy", "10")
442 with mock
.patch
.object(self
.s
, "load_markets") as load_markets
,\
443 mock
.patch
.object(self
.s
, "privatePostMarginBuy") as margin_buy
,\
444 mock
.patch
.object(self
.s
, "privatePostMarginSell") as margin_sell
,\
445 mock
.patch
.object(self
.s
, "market") as market_mock
,\
446 mock
.patch
.object(self
.s
, "price_to_precision") as ptp
,\
447 mock
.patch
.object(self
.s
, "amount_to_precision") as atp
:
449 margin_buy
.return_value
= {
452 margin_sell
.return_value
= {
455 market_mock
.return_value
= { "id": "BTC_ETC", "symbol": "BTC_ETC" }
456 ptp
.return_value
= D("0.1")
457 atp
.return_value
= D("12")
459 order
= self
.s
.create_margin_order("BTC_ETC", "margin", "buy", "12", price
="0.1")
460 self
.assertEqual(123, order
["id"])
461 margin_buy
.assert_called_once_with({"currencyPair": "BTC_ETC", "rate": D("0.1"), "amount": D("12")}
)
462 margin_sell
.assert_not_called()
463 margin_buy
.reset_mock()
464 margin_sell
.reset_mock()
466 order
= self
.s
.create_margin_order("BTC_ETC", "margin", "sell", "12", lending_rate
="0.01", price
="0.1")
467 self
.assertEqual(456, order
["id"])
468 margin_sell
.assert_called_once_with({"currencyPair": "BTC_ETC", "rate": D("0.1"), "amount": D("12"), "lendingRate": "0.01"}
)
469 margin_buy
.assert_not_called()
471 def test_create_exchange_order(self
):
472 with mock
.patch
.object(market
.ccxt
.poloniex
, "create_order") as create_order
:
473 self
.s
.create_order("symbol", "type", "side", "amount", price
="price", params
="params")
475 create_order
.assert_called_once_with("symbol", "type", "side", "amount", price
="price", params
="params")