ccxt 4.2.76__py2.py3-none-any.whl → 4.4.48__py2.py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (546) hide show
  1. ccxt/__init__.py +36 -14
  2. ccxt/abstract/alpaca.py +4 -0
  3. ccxt/abstract/bigone.py +1 -1
  4. ccxt/abstract/binance.py +112 -48
  5. ccxt/abstract/binancecoinm.py +112 -48
  6. ccxt/abstract/binanceus.py +147 -83
  7. ccxt/abstract/binanceusdm.py +112 -48
  8. ccxt/abstract/bingx.py +133 -78
  9. ccxt/abstract/bitbank.py +5 -0
  10. ccxt/abstract/bitfinex.py +136 -65
  11. ccxt/abstract/bitfinex1.py +69 -0
  12. ccxt/abstract/bitflyer.py +1 -0
  13. ccxt/abstract/bitget.py +8 -1
  14. ccxt/abstract/bitmart.py +13 -1
  15. ccxt/abstract/bitopro.py +1 -0
  16. ccxt/abstract/bitpanda.py +0 -12
  17. ccxt/abstract/bitrue.py +3 -3
  18. ccxt/abstract/bitstamp.py +26 -3
  19. ccxt/abstract/blofin.py +24 -0
  20. ccxt/abstract/btcbox.py +1 -0
  21. ccxt/abstract/bybit.py +29 -14
  22. ccxt/abstract/cex.py +28 -29
  23. ccxt/abstract/coinbase.py +6 -0
  24. ccxt/abstract/coinbaseadvanced.py +94 -0
  25. ccxt/abstract/{coinbasepro.py → coinbaseexchange.py} +1 -0
  26. ccxt/abstract/coinbaseinternational.py +1 -1
  27. ccxt/abstract/coincatch.py +94 -0
  28. ccxt/abstract/coinex.py +233 -123
  29. ccxt/abstract/coinmetro.py +1 -0
  30. ccxt/abstract/cryptocom.py +14 -0
  31. ccxt/abstract/defx.py +69 -0
  32. ccxt/abstract/deribit.py +1 -0
  33. ccxt/abstract/digifinex.py +1 -0
  34. ccxt/abstract/ellipx.py +25 -0
  35. ccxt/abstract/gate.py +20 -0
  36. ccxt/abstract/gateio.py +20 -0
  37. ccxt/abstract/gemini.py +1 -0
  38. ccxt/abstract/hashkey.py +67 -0
  39. ccxt/abstract/hyperliquid.py +1 -1
  40. ccxt/abstract/independentreserve.py +6 -0
  41. ccxt/abstract/kraken.py +4 -3
  42. ccxt/abstract/krakenfutures.py +4 -0
  43. ccxt/abstract/kucoin.py +25 -0
  44. ccxt/abstract/kucoinfutures.py +35 -0
  45. ccxt/abstract/luno.py +2 -0
  46. ccxt/abstract/mexc.py +4 -0
  47. ccxt/abstract/myokx.py +340 -0
  48. ccxt/abstract/oceanex.py +5 -0
  49. ccxt/abstract/okx.py +30 -0
  50. ccxt/abstract/onetrading.py +0 -12
  51. ccxt/abstract/oxfun.py +34 -0
  52. ccxt/abstract/paradex.py +40 -0
  53. ccxt/abstract/phemex.py +1 -0
  54. ccxt/abstract/upbit.py +4 -0
  55. ccxt/abstract/vertex.py +19 -0
  56. ccxt/abstract/whitebit.py +31 -1
  57. ccxt/abstract/woo.py +6 -2
  58. ccxt/abstract/woofipro.py +119 -0
  59. ccxt/abstract/xt.py +153 -0
  60. ccxt/abstract/zonda.py +6 -0
  61. ccxt/ace.py +164 -60
  62. ccxt/alpaca.py +727 -63
  63. ccxt/ascendex.py +395 -249
  64. ccxt/async_support/__init__.py +36 -14
  65. ccxt/async_support/ace.py +164 -60
  66. ccxt/async_support/alpaca.py +727 -63
  67. ccxt/async_support/ascendex.py +396 -249
  68. ccxt/async_support/base/exchange.py +531 -155
  69. ccxt/async_support/base/ws/aiohttp_client.py +28 -5
  70. ccxt/async_support/base/ws/cache.py +3 -2
  71. ccxt/async_support/base/ws/client.py +26 -5
  72. ccxt/async_support/base/ws/fast_client.py +4 -3
  73. ccxt/async_support/base/ws/functions.py +1 -1
  74. ccxt/async_support/base/ws/future.py +40 -31
  75. ccxt/async_support/base/ws/order_book_side.py +3 -0
  76. ccxt/async_support/bequant.py +1 -1
  77. ccxt/async_support/bigone.py +329 -202
  78. ccxt/async_support/binance.py +3513 -1511
  79. ccxt/async_support/binancecoinm.py +2 -1
  80. ccxt/async_support/binanceus.py +12 -1
  81. ccxt/async_support/binanceusdm.py +3 -1
  82. ccxt/async_support/bingx.py +3105 -881
  83. ccxt/async_support/bit2c.py +119 -38
  84. ccxt/async_support/bitbank.py +215 -76
  85. ccxt/async_support/bitbns.py +124 -53
  86. ccxt/async_support/bitfinex.py +3236 -1078
  87. ccxt/async_support/bitfinex1.py +1711 -0
  88. ccxt/async_support/bitflyer.py +239 -50
  89. ccxt/async_support/bitget.py +1513 -563
  90. ccxt/async_support/bithumb.py +201 -67
  91. ccxt/async_support/bitmart.py +1320 -435
  92. ccxt/async_support/bitmex.py +308 -111
  93. ccxt/async_support/bitopro.py +256 -96
  94. ccxt/async_support/bitrue.py +365 -233
  95. ccxt/async_support/bitso.py +201 -89
  96. ccxt/async_support/bitstamp.py +438 -269
  97. ccxt/async_support/bitteam.py +179 -73
  98. ccxt/async_support/bitvavo.py +180 -70
  99. ccxt/async_support/bl3p.py +92 -25
  100. ccxt/async_support/blockchaincom.py +193 -79
  101. ccxt/async_support/blofin.py +403 -150
  102. ccxt/async_support/btcalpha.py +161 -55
  103. ccxt/async_support/btcbox.py +250 -34
  104. ccxt/async_support/btcmarkets.py +232 -85
  105. ccxt/async_support/btcturk.py +159 -60
  106. ccxt/async_support/bybit.py +2326 -1255
  107. ccxt/async_support/cex.py +1409 -1329
  108. ccxt/async_support/coinbase.py +1455 -288
  109. ccxt/async_support/coinbaseadvanced.py +17 -0
  110. ccxt/async_support/{coinbasepro.py → coinbaseexchange.py} +233 -99
  111. ccxt/async_support/coinbaseinternational.py +428 -88
  112. ccxt/async_support/coincatch.py +5152 -0
  113. ccxt/async_support/coincheck.py +121 -38
  114. ccxt/async_support/coinex.py +4020 -3339
  115. ccxt/async_support/coinlist.py +273 -116
  116. ccxt/async_support/coinmate.py +204 -97
  117. ccxt/async_support/coinmetro.py +203 -110
  118. ccxt/async_support/coinone.py +142 -68
  119. ccxt/async_support/coinsph.py +206 -89
  120. ccxt/async_support/coinspot.py +137 -62
  121. ccxt/async_support/cryptocom.py +515 -185
  122. ccxt/async_support/currencycom.py +203 -85
  123. ccxt/async_support/defx.py +2066 -0
  124. ccxt/async_support/delta.py +467 -158
  125. ccxt/async_support/deribit.py +558 -324
  126. ccxt/async_support/digifinex.py +340 -223
  127. ccxt/async_support/ellipx.py +1826 -0
  128. ccxt/async_support/exmo.py +259 -128
  129. ccxt/async_support/gate.py +1473 -464
  130. ccxt/async_support/gemini.py +206 -84
  131. ccxt/async_support/hashkey.py +4164 -0
  132. ccxt/async_support/hitbtc.py +334 -178
  133. ccxt/async_support/hollaex.py +134 -83
  134. ccxt/async_support/htx.py +1095 -563
  135. ccxt/async_support/huobijp.py +105 -56
  136. ccxt/async_support/hyperliquid.py +1634 -269
  137. ccxt/async_support/idex.py +148 -95
  138. ccxt/async_support/independentreserve.py +236 -31
  139. ccxt/async_support/indodax.py +165 -62
  140. ccxt/async_support/kraken.py +871 -354
  141. ccxt/async_support/krakenfutures.py +324 -100
  142. ccxt/async_support/kucoin.py +1050 -355
  143. ccxt/async_support/kucoinfutures.py +1004 -149
  144. ccxt/async_support/kuna.py +138 -106
  145. ccxt/async_support/latoken.py +135 -79
  146. ccxt/async_support/lbank.py +290 -113
  147. ccxt/async_support/luno.py +112 -62
  148. ccxt/async_support/lykke.py +104 -55
  149. ccxt/async_support/mercado.py +36 -29
  150. ccxt/async_support/mexc.py +995 -429
  151. ccxt/async_support/myokx.py +43 -0
  152. ccxt/async_support/ndax.py +163 -82
  153. ccxt/async_support/novadax.py +121 -75
  154. ccxt/async_support/oceanex.py +175 -59
  155. ccxt/async_support/okcoin.py +222 -163
  156. ccxt/async_support/okx.py +1777 -455
  157. ccxt/async_support/onetrading.py +132 -414
  158. ccxt/async_support/oxfun.py +2832 -0
  159. ccxt/async_support/p2b.py +79 -51
  160. ccxt/async_support/paradex.py +2017 -0
  161. ccxt/async_support/paymium.py +56 -32
  162. ccxt/async_support/phemex.py +572 -196
  163. ccxt/async_support/poloniex.py +218 -95
  164. ccxt/async_support/poloniexfutures.py +260 -92
  165. ccxt/async_support/probit.py +143 -110
  166. ccxt/async_support/timex.py +123 -70
  167. ccxt/async_support/tokocrypto.py +129 -93
  168. ccxt/async_support/tradeogre.py +39 -25
  169. ccxt/async_support/upbit.py +322 -113
  170. ccxt/async_support/vertex.py +2983 -0
  171. ccxt/async_support/wavesexchange.py +227 -173
  172. ccxt/async_support/wazirx.py +145 -65
  173. ccxt/async_support/whitebit.py +533 -138
  174. ccxt/async_support/woo.py +1155 -295
  175. ccxt/async_support/woofipro.py +2716 -0
  176. ccxt/async_support/xt.py +4628 -0
  177. ccxt/async_support/yobit.py +160 -92
  178. ccxt/async_support/zaif.py +80 -33
  179. ccxt/async_support/zonda.py +140 -69
  180. ccxt/base/errors.py +51 -20
  181. ccxt/base/exchange.py +1729 -482
  182. ccxt/base/precise.py +10 -0
  183. ccxt/base/types.py +223 -4
  184. ccxt/bequant.py +1 -1
  185. ccxt/bigone.py +329 -202
  186. ccxt/binance.py +3513 -1511
  187. ccxt/binancecoinm.py +2 -1
  188. ccxt/binanceus.py +12 -1
  189. ccxt/binanceusdm.py +3 -1
  190. ccxt/bingx.py +3105 -881
  191. ccxt/bit2c.py +119 -38
  192. ccxt/bitbank.py +215 -76
  193. ccxt/bitbns.py +124 -53
  194. ccxt/bitfinex.py +3235 -1078
  195. ccxt/bitfinex1.py +1710 -0
  196. ccxt/bitflyer.py +239 -50
  197. ccxt/bitget.py +1513 -563
  198. ccxt/bithumb.py +200 -67
  199. ccxt/bitmart.py +1320 -435
  200. ccxt/bitmex.py +308 -111
  201. ccxt/bitopro.py +256 -96
  202. ccxt/bitrue.py +365 -233
  203. ccxt/bitso.py +201 -89
  204. ccxt/bitstamp.py +438 -269
  205. ccxt/bitteam.py +179 -73
  206. ccxt/bitvavo.py +180 -70
  207. ccxt/bl3p.py +92 -25
  208. ccxt/blockchaincom.py +193 -79
  209. ccxt/blofin.py +403 -150
  210. ccxt/btcalpha.py +161 -55
  211. ccxt/btcbox.py +250 -34
  212. ccxt/btcmarkets.py +232 -85
  213. ccxt/btcturk.py +159 -60
  214. ccxt/bybit.py +2326 -1255
  215. ccxt/cex.py +1408 -1329
  216. ccxt/coinbase.py +1455 -288
  217. ccxt/coinbaseadvanced.py +17 -0
  218. ccxt/{coinbasepro.py → coinbaseexchange.py} +233 -99
  219. ccxt/coinbaseinternational.py +428 -88
  220. ccxt/coincatch.py +5152 -0
  221. ccxt/coincheck.py +121 -38
  222. ccxt/coinex.py +4020 -3339
  223. ccxt/coinlist.py +273 -116
  224. ccxt/coinmate.py +204 -97
  225. ccxt/coinmetro.py +203 -110
  226. ccxt/coinone.py +142 -68
  227. ccxt/coinsph.py +206 -89
  228. ccxt/coinspot.py +137 -62
  229. ccxt/cryptocom.py +515 -185
  230. ccxt/currencycom.py +203 -85
  231. ccxt/defx.py +2065 -0
  232. ccxt/delta.py +467 -158
  233. ccxt/deribit.py +558 -324
  234. ccxt/digifinex.py +340 -223
  235. ccxt/ellipx.py +1826 -0
  236. ccxt/exmo.py +259 -128
  237. ccxt/gate.py +1473 -464
  238. ccxt/gemini.py +206 -84
  239. ccxt/hashkey.py +4164 -0
  240. ccxt/hitbtc.py +334 -178
  241. ccxt/hollaex.py +134 -83
  242. ccxt/htx.py +1095 -563
  243. ccxt/huobijp.py +105 -56
  244. ccxt/hyperliquid.py +1633 -269
  245. ccxt/idex.py +148 -95
  246. ccxt/independentreserve.py +235 -31
  247. ccxt/indodax.py +165 -62
  248. ccxt/kraken.py +871 -354
  249. ccxt/krakenfutures.py +324 -100
  250. ccxt/kucoin.py +1050 -355
  251. ccxt/kucoinfutures.py +1004 -149
  252. ccxt/kuna.py +138 -106
  253. ccxt/latoken.py +135 -79
  254. ccxt/lbank.py +290 -113
  255. ccxt/luno.py +112 -62
  256. ccxt/lykke.py +104 -55
  257. ccxt/mercado.py +36 -29
  258. ccxt/mexc.py +994 -429
  259. ccxt/myokx.py +43 -0
  260. ccxt/ndax.py +163 -82
  261. ccxt/novadax.py +121 -75
  262. ccxt/oceanex.py +175 -59
  263. ccxt/okcoin.py +222 -163
  264. ccxt/okx.py +1777 -455
  265. ccxt/onetrading.py +132 -414
  266. ccxt/oxfun.py +2831 -0
  267. ccxt/p2b.py +79 -51
  268. ccxt/paradex.py +2017 -0
  269. ccxt/paymium.py +56 -32
  270. ccxt/phemex.py +572 -196
  271. ccxt/poloniex.py +218 -95
  272. ccxt/poloniexfutures.py +260 -92
  273. ccxt/pro/__init__.py +29 -5
  274. ccxt/pro/alpaca.py +32 -17
  275. ccxt/pro/ascendex.py +63 -15
  276. ccxt/pro/bequant.py +4 -0
  277. ccxt/pro/binance.py +1596 -329
  278. ccxt/pro/binancecoinm.py +1 -0
  279. ccxt/pro/binanceus.py +2 -9
  280. ccxt/pro/binanceusdm.py +2 -0
  281. ccxt/pro/bingx.py +527 -134
  282. ccxt/pro/bitcoincom.py +4 -1
  283. ccxt/pro/bitfinex.py +731 -266
  284. ccxt/pro/bitfinex1.py +635 -0
  285. ccxt/pro/bitget.py +726 -357
  286. ccxt/pro/bithumb.py +380 -0
  287. ccxt/pro/bitmart.py +138 -39
  288. ccxt/pro/bitmex.py +199 -40
  289. ccxt/pro/bitopro.py +25 -13
  290. ccxt/pro/bitrue.py +31 -32
  291. ccxt/pro/bitstamp.py +7 -6
  292. ccxt/pro/bitvavo.py +204 -82
  293. ccxt/pro/blockchaincom.py +30 -17
  294. ccxt/pro/blofin.py +692 -0
  295. ccxt/pro/bybit.py +791 -82
  296. ccxt/pro/cex.py +99 -51
  297. ccxt/pro/coinbase.py +220 -30
  298. ccxt/{async_support/hitbtc3.py → pro/coinbaseadvanced.py} +5 -5
  299. ccxt/pro/{coinbasepro.py → coinbaseexchange.py} +19 -19
  300. ccxt/pro/coinbaseinternational.py +193 -30
  301. ccxt/pro/coincatch.py +1464 -0
  302. ccxt/pro/coincheck.py +11 -6
  303. ccxt/pro/coinex.py +967 -661
  304. ccxt/pro/coinone.py +17 -10
  305. ccxt/pro/cryptocom.py +446 -66
  306. ccxt/pro/currencycom.py +11 -10
  307. ccxt/pro/defx.py +832 -0
  308. ccxt/pro/deribit.py +168 -32
  309. ccxt/pro/exmo.py +253 -21
  310. ccxt/pro/gate.py +729 -64
  311. ccxt/pro/gemini.py +44 -26
  312. ccxt/pro/hashkey.py +802 -0
  313. ccxt/pro/hitbtc.py +208 -103
  314. ccxt/pro/hollaex.py +25 -9
  315. ccxt/pro/htx.py +83 -39
  316. ccxt/pro/huobijp.py +17 -16
  317. ccxt/pro/hyperliquid.py +502 -31
  318. ccxt/pro/idex.py +28 -13
  319. ccxt/pro/independentreserve.py +21 -16
  320. ccxt/pro/kraken.py +298 -51
  321. ccxt/pro/krakenfutures.py +166 -75
  322. ccxt/pro/kucoin.py +395 -77
  323. ccxt/pro/kucoinfutures.py +400 -99
  324. ccxt/pro/lbank.py +52 -31
  325. ccxt/pro/luno.py +12 -10
  326. ccxt/pro/mexc.py +400 -50
  327. ccxt/pro/myokx.py +28 -0
  328. ccxt/pro/ndax.py +25 -12
  329. ccxt/pro/okcoin.py +28 -9
  330. ccxt/pro/okx.py +935 -124
  331. ccxt/pro/onetrading.py +41 -24
  332. ccxt/pro/oxfun.py +1054 -0
  333. ccxt/pro/p2b.py +100 -24
  334. ccxt/pro/paradex.py +352 -0
  335. ccxt/pro/phemex.py +93 -34
  336. ccxt/pro/poloniex.py +129 -50
  337. ccxt/pro/poloniexfutures.py +53 -32
  338. ccxt/pro/probit.py +93 -86
  339. ccxt/pro/upbit.py +401 -8
  340. ccxt/pro/vertex.py +943 -0
  341. ccxt/pro/wazirx.py +46 -28
  342. ccxt/pro/whitebit.py +65 -12
  343. ccxt/pro/woo.py +486 -70
  344. ccxt/pro/woofipro.py +1271 -0
  345. ccxt/pro/xt.py +1067 -0
  346. ccxt/probit.py +143 -110
  347. ccxt/static_dependencies/__init__.py +1 -1
  348. ccxt/static_dependencies/lark/__init__.py +38 -0
  349. ccxt/static_dependencies/lark/__pyinstaller/__init__.py +6 -0
  350. ccxt/static_dependencies/lark/__pyinstaller/hook-lark.py +14 -0
  351. ccxt/static_dependencies/lark/ast_utils.py +59 -0
  352. ccxt/static_dependencies/lark/common.py +86 -0
  353. ccxt/static_dependencies/lark/exceptions.py +292 -0
  354. ccxt/static_dependencies/lark/grammar.py +130 -0
  355. ccxt/static_dependencies/lark/grammars/__init__.py +0 -0
  356. ccxt/static_dependencies/lark/indenter.py +143 -0
  357. ccxt/static_dependencies/lark/lark.py +658 -0
  358. ccxt/static_dependencies/lark/lexer.py +678 -0
  359. ccxt/static_dependencies/lark/load_grammar.py +1428 -0
  360. ccxt/static_dependencies/lark/parse_tree_builder.py +391 -0
  361. ccxt/static_dependencies/lark/parser_frontends.py +257 -0
  362. ccxt/static_dependencies/lark/parsers/__init__.py +0 -0
  363. ccxt/static_dependencies/lark/parsers/cyk.py +340 -0
  364. ccxt/static_dependencies/lark/parsers/earley.py +314 -0
  365. ccxt/static_dependencies/lark/parsers/earley_common.py +42 -0
  366. ccxt/static_dependencies/lark/parsers/earley_forest.py +801 -0
  367. ccxt/static_dependencies/lark/parsers/grammar_analysis.py +203 -0
  368. ccxt/static_dependencies/lark/parsers/lalr_analysis.py +332 -0
  369. ccxt/static_dependencies/lark/parsers/lalr_interactive_parser.py +158 -0
  370. ccxt/static_dependencies/lark/parsers/lalr_parser.py +122 -0
  371. ccxt/static_dependencies/lark/parsers/lalr_parser_state.py +110 -0
  372. ccxt/static_dependencies/lark/parsers/xearley.py +165 -0
  373. ccxt/static_dependencies/lark/py.typed +0 -0
  374. ccxt/static_dependencies/lark/reconstruct.py +107 -0
  375. ccxt/static_dependencies/lark/tools/__init__.py +70 -0
  376. ccxt/static_dependencies/lark/tools/nearley.py +202 -0
  377. ccxt/static_dependencies/lark/tools/serialize.py +32 -0
  378. ccxt/static_dependencies/lark/tools/standalone.py +196 -0
  379. ccxt/static_dependencies/lark/tree.py +267 -0
  380. ccxt/static_dependencies/lark/tree_matcher.py +186 -0
  381. ccxt/static_dependencies/lark/tree_templates.py +180 -0
  382. ccxt/static_dependencies/lark/utils.py +343 -0
  383. ccxt/static_dependencies/lark/visitors.py +596 -0
  384. ccxt/static_dependencies/marshmallow/__init__.py +81 -0
  385. ccxt/static_dependencies/marshmallow/base.py +65 -0
  386. ccxt/static_dependencies/marshmallow/class_registry.py +94 -0
  387. ccxt/static_dependencies/marshmallow/decorators.py +231 -0
  388. ccxt/static_dependencies/marshmallow/error_store.py +60 -0
  389. ccxt/static_dependencies/marshmallow/exceptions.py +71 -0
  390. ccxt/static_dependencies/marshmallow/fields.py +2114 -0
  391. ccxt/static_dependencies/marshmallow/orderedset.py +89 -0
  392. ccxt/static_dependencies/marshmallow/py.typed +0 -0
  393. ccxt/static_dependencies/marshmallow/schema.py +1228 -0
  394. ccxt/static_dependencies/marshmallow/types.py +12 -0
  395. ccxt/static_dependencies/marshmallow/utils.py +378 -0
  396. ccxt/static_dependencies/marshmallow/validate.py +678 -0
  397. ccxt/static_dependencies/marshmallow/warnings.py +2 -0
  398. ccxt/static_dependencies/marshmallow_dataclass/__init__.py +1047 -0
  399. ccxt/static_dependencies/marshmallow_dataclass/collection_field.py +51 -0
  400. ccxt/static_dependencies/marshmallow_dataclass/lazy_class_attribute.py +45 -0
  401. ccxt/static_dependencies/marshmallow_dataclass/mypy.py +71 -0
  402. ccxt/static_dependencies/marshmallow_dataclass/py.typed +0 -0
  403. ccxt/static_dependencies/marshmallow_dataclass/typing.py +14 -0
  404. ccxt/static_dependencies/marshmallow_dataclass/union_field.py +82 -0
  405. ccxt/static_dependencies/marshmallow_oneofschema/__init__.py +1 -0
  406. ccxt/static_dependencies/marshmallow_oneofschema/one_of_schema.py +193 -0
  407. ccxt/static_dependencies/marshmallow_oneofschema/py.typed +0 -0
  408. ccxt/static_dependencies/starknet/__init__.py +0 -0
  409. ccxt/static_dependencies/starknet/cairo/__init__.py +0 -0
  410. ccxt/static_dependencies/starknet/cairo/data_types.py +123 -0
  411. ccxt/static_dependencies/starknet/cairo/deprecated_parse/__init__.py +0 -0
  412. ccxt/static_dependencies/starknet/cairo/deprecated_parse/cairo_types.py +77 -0
  413. ccxt/static_dependencies/starknet/cairo/deprecated_parse/parser.py +46 -0
  414. ccxt/static_dependencies/starknet/cairo/deprecated_parse/parser_transformer.py +138 -0
  415. ccxt/static_dependencies/starknet/cairo/felt.py +64 -0
  416. ccxt/static_dependencies/starknet/cairo/type_parser.py +121 -0
  417. ccxt/static_dependencies/starknet/cairo/v1/__init__.py +0 -0
  418. ccxt/static_dependencies/starknet/cairo/v1/type_parser.py +59 -0
  419. ccxt/static_dependencies/starknet/cairo/v2/__init__.py +0 -0
  420. ccxt/static_dependencies/starknet/cairo/v2/type_parser.py +77 -0
  421. ccxt/static_dependencies/starknet/ccxt_utils.py +7 -0
  422. ccxt/static_dependencies/starknet/common.py +15 -0
  423. ccxt/static_dependencies/starknet/constants.py +39 -0
  424. ccxt/static_dependencies/starknet/hash/__init__.py +0 -0
  425. ccxt/static_dependencies/starknet/hash/address.py +79 -0
  426. ccxt/static_dependencies/starknet/hash/compiled_class_hash_objects.py +111 -0
  427. ccxt/static_dependencies/starknet/hash/selector.py +16 -0
  428. ccxt/static_dependencies/starknet/hash/storage.py +12 -0
  429. ccxt/static_dependencies/starknet/hash/utils.py +78 -0
  430. ccxt/static_dependencies/starknet/models/__init__.py +0 -0
  431. ccxt/static_dependencies/starknet/models/typed_data.py +45 -0
  432. ccxt/static_dependencies/starknet/serialization/__init__.py +24 -0
  433. ccxt/static_dependencies/starknet/serialization/_calldata_reader.py +40 -0
  434. ccxt/static_dependencies/starknet/serialization/_context.py +142 -0
  435. ccxt/static_dependencies/starknet/serialization/data_serializers/__init__.py +10 -0
  436. ccxt/static_dependencies/starknet/serialization/data_serializers/_common.py +82 -0
  437. ccxt/static_dependencies/starknet/serialization/data_serializers/array_serializer.py +43 -0
  438. ccxt/static_dependencies/starknet/serialization/data_serializers/bool_serializer.py +37 -0
  439. ccxt/static_dependencies/starknet/serialization/data_serializers/byte_array_serializer.py +66 -0
  440. ccxt/static_dependencies/starknet/serialization/data_serializers/cairo_data_serializer.py +71 -0
  441. ccxt/static_dependencies/starknet/serialization/data_serializers/enum_serializer.py +71 -0
  442. ccxt/static_dependencies/starknet/serialization/data_serializers/felt_serializer.py +50 -0
  443. ccxt/static_dependencies/starknet/serialization/data_serializers/named_tuple_serializer.py +58 -0
  444. ccxt/static_dependencies/starknet/serialization/data_serializers/option_serializer.py +43 -0
  445. ccxt/static_dependencies/starknet/serialization/data_serializers/output_serializer.py +40 -0
  446. ccxt/static_dependencies/starknet/serialization/data_serializers/payload_serializer.py +72 -0
  447. ccxt/static_dependencies/starknet/serialization/data_serializers/struct_serializer.py +36 -0
  448. ccxt/static_dependencies/starknet/serialization/data_serializers/tuple_serializer.py +36 -0
  449. ccxt/static_dependencies/starknet/serialization/data_serializers/uint256_serializer.py +76 -0
  450. ccxt/static_dependencies/starknet/serialization/data_serializers/uint_serializer.py +100 -0
  451. ccxt/static_dependencies/starknet/serialization/data_serializers/unit_serializer.py +32 -0
  452. ccxt/static_dependencies/starknet/serialization/errors.py +10 -0
  453. ccxt/static_dependencies/starknet/serialization/factory.py +229 -0
  454. ccxt/static_dependencies/starknet/serialization/function_serialization_adapter.py +110 -0
  455. ccxt/static_dependencies/starknet/serialization/tuple_dataclass.py +59 -0
  456. ccxt/static_dependencies/starknet/utils/__init__.py +0 -0
  457. ccxt/static_dependencies/starknet/utils/constructor_args_translator.py +86 -0
  458. ccxt/static_dependencies/starknet/utils/iterable.py +13 -0
  459. ccxt/static_dependencies/starknet/utils/schema.py +13 -0
  460. ccxt/static_dependencies/starknet/utils/typed_data.py +182 -0
  461. ccxt/static_dependencies/starkware/__init__.py +0 -0
  462. ccxt/static_dependencies/starkware/crypto/__init__.py +0 -0
  463. ccxt/static_dependencies/starkware/crypto/fast_pedersen_hash.py +50 -0
  464. ccxt/static_dependencies/starkware/crypto/math_utils.py +78 -0
  465. ccxt/static_dependencies/starkware/crypto/signature.py +2344 -0
  466. ccxt/static_dependencies/starkware/crypto/utils.py +63 -0
  467. ccxt/static_dependencies/sympy/__init__.py +0 -0
  468. ccxt/static_dependencies/sympy/core/__init__.py +0 -0
  469. ccxt/static_dependencies/sympy/core/intfunc.py +35 -0
  470. ccxt/static_dependencies/sympy/external/__init__.py +0 -0
  471. ccxt/static_dependencies/sympy/external/gmpy.py +345 -0
  472. ccxt/static_dependencies/sympy/external/importtools.py +187 -0
  473. ccxt/static_dependencies/sympy/external/ntheory.py +637 -0
  474. ccxt/static_dependencies/sympy/external/pythonmpq.py +341 -0
  475. ccxt/static_dependencies/typing_inspect/__init__.py +0 -0
  476. ccxt/static_dependencies/typing_inspect/typing_inspect.py +851 -0
  477. ccxt/test/{test_async.py → tests_async.py} +465 -407
  478. ccxt/test/tests_helpers.py +285 -0
  479. ccxt/test/tests_init.py +39 -0
  480. ccxt/test/{test_sync.py → tests_sync.py} +465 -409
  481. ccxt/timex.py +123 -70
  482. ccxt/tokocrypto.py +129 -93
  483. ccxt/tradeogre.py +39 -25
  484. ccxt/upbit.py +322 -113
  485. ccxt/vertex.py +2983 -0
  486. ccxt/wavesexchange.py +227 -173
  487. ccxt/wazirx.py +145 -65
  488. ccxt/whitebit.py +533 -138
  489. ccxt/woo.py +1155 -295
  490. ccxt/woofipro.py +2716 -0
  491. ccxt/xt.py +4627 -0
  492. ccxt/yobit.py +159 -92
  493. ccxt/zaif.py +80 -33
  494. ccxt/zonda.py +140 -69
  495. ccxt-4.4.48.dist-info/LICENSE.txt +21 -0
  496. ccxt-4.4.48.dist-info/METADATA +646 -0
  497. ccxt-4.4.48.dist-info/RECORD +669 -0
  498. {ccxt-4.2.76.dist-info → ccxt-4.4.48.dist-info}/WHEEL +1 -1
  499. ccxt/abstract/bitbay.py +0 -47
  500. ccxt/abstract/bitfinex2.py +0 -139
  501. ccxt/abstract/hitbtc3.py +0 -115
  502. ccxt/async_support/bitbay.py +0 -17
  503. ccxt/async_support/bitfinex2.py +0 -3496
  504. ccxt/async_support/flowbtc.py +0 -34
  505. ccxt/bitbay.py +0 -17
  506. ccxt/bitfinex2.py +0 -3496
  507. ccxt/flowbtc.py +0 -34
  508. ccxt/hitbtc3.py +0 -16
  509. ccxt/pro/bitfinex2.py +0 -1081
  510. ccxt/test/base/__init__.py +0 -28
  511. ccxt/test/base/test_account.py +0 -26
  512. ccxt/test/base/test_balance.py +0 -56
  513. ccxt/test/base/test_borrow_interest.py +0 -35
  514. ccxt/test/base/test_borrow_rate.py +0 -32
  515. ccxt/test/base/test_calculate_fee.py +0 -51
  516. ccxt/test/base/test_crypto.py +0 -127
  517. ccxt/test/base/test_currency.py +0 -76
  518. ccxt/test/base/test_datetime.py +0 -103
  519. ccxt/test/base/test_decimal_to_precision.py +0 -392
  520. ccxt/test/base/test_deep_extend.py +0 -68
  521. ccxt/test/base/test_deposit_withdrawal.py +0 -50
  522. ccxt/test/base/test_exchange_datetime_functions.py +0 -76
  523. ccxt/test/base/test_funding_rate_history.py +0 -29
  524. ccxt/test/base/test_last_price.py +0 -32
  525. ccxt/test/base/test_ledger_entry.py +0 -45
  526. ccxt/test/base/test_ledger_item.py +0 -48
  527. ccxt/test/base/test_leverage_tier.py +0 -33
  528. ccxt/test/base/test_margin_mode.py +0 -24
  529. ccxt/test/base/test_margin_modification.py +0 -35
  530. ccxt/test/base/test_market.py +0 -190
  531. ccxt/test/base/test_number.py +0 -411
  532. ccxt/test/base/test_ohlcv.py +0 -32
  533. ccxt/test/base/test_open_interest.py +0 -32
  534. ccxt/test/base/test_order.py +0 -64
  535. ccxt/test/base/test_order_book.py +0 -63
  536. ccxt/test/base/test_position.py +0 -60
  537. ccxt/test/base/test_shared_methods.py +0 -345
  538. ccxt/test/base/test_status.py +0 -24
  539. ccxt/test/base/test_throttle.py +0 -126
  540. ccxt/test/base/test_ticker.py +0 -86
  541. ccxt/test/base/test_trade.py +0 -47
  542. ccxt/test/base/test_trading_fee.py +0 -26
  543. ccxt/test/base/test_transaction.py +0 -39
  544. ccxt-4.2.76.dist-info/METADATA +0 -626
  545. ccxt-4.2.76.dist-info/RECORD +0 -534
  546. {ccxt-4.2.76.dist-info → ccxt-4.4.48.dist-info}/top_level.txt +0 -0
@@ -1,272 +1,36 @@
1
1
  # -*- coding: utf-8 -*-
2
2
 
3
- import argparse
4
- import json
5
- # import logging
6
- import os
7
- import sys
8
- from traceback import format_tb, format_exception
9
-
10
- import importlib # noqa: E402
11
- import re
12
-
13
- # ------------------------------------------------------------------------------
14
- # logging.basicConfig(level=logging.INFO)
15
- # ------------------------------------------------------------------------------
16
- DIR_NAME = os.path.dirname(os.path.abspath(__file__))
17
- root = os.path.dirname(os.path.dirname(DIR_NAME))
18
- sys.path.append(root)
19
-
20
- import ccxt # noqa: E402
21
- import ccxt.pro as ccxtpro # noqa: E402
22
-
23
- # ------------------------------------------------------------------------------
24
- # from typing import Optional
25
- # from typing import List
26
- from ccxt.base.errors import NotSupported
27
- from ccxt.base.errors import ProxyError
28
- from ccxt.base.errors import OperationFailed
29
- # from ccxt.base.errors import ExchangeError
30
- from ccxt.base.errors import ExchangeNotAvailable
31
- from ccxt.base.errors import OnMaintenance
32
- from ccxt.base.errors import AuthenticationError
33
-
34
- # ------------------------------------------------------------------------------
35
-
36
- class Argv(object):
37
- id_tests = False
38
- static_tests = False
39
- ws_tests = False
40
- request_tests = False
41
- response_tests = False
42
-
43
- sandbox = False
44
- privateOnly = False
45
- private = False
46
- ws = False
47
- verbose = False
48
- nonce = None
49
- exchange = None
50
- symbol = None
51
- info = False
52
- pass
53
-
54
-
55
- argv = Argv()
56
- parser = argparse.ArgumentParser()
57
-
58
- parser.add_argument('--sandbox', action='store_true', help='enable sandbox mode')
59
- parser.add_argument('--privateOnly', action='store_true', help='run private tests only')
60
- parser.add_argument('--private', action='store_true', help='run private tests')
61
- parser.add_argument('--verbose', action='store_true', help='enable verbose output')
62
- parser.add_argument('--ws', action='store_true', help='websockets version')
63
- parser.add_argument('--info', action='store_true', help='enable info output')
64
- parser.add_argument('--static', action='store_true', help='run static tests')
65
- parser.add_argument('--useProxy', action='store_true', help='run static tests')
66
- parser.add_argument('--idTests', action='store_true', help='run brokerId tests')
67
- parser.add_argument('--responseTests', action='store_true', help='run response tests')
68
- parser.add_argument('--requestTests', action='store_true', help='run response tests')
69
- parser.add_argument('--nonce', type=int, help='integer')
70
- parser.add_argument('exchange', type=str, help='exchange id in lowercase', nargs='?')
71
- parser.add_argument('symbol', type=str, help='symbol in uppercase', nargs='?')
72
- parser.parse_args(namespace=argv)
73
-
74
- # ------------------------------------------------------------------------------
75
-
76
- path = os.path.dirname(ccxt.__file__)
77
- if 'site-packages' in os.path.dirname(ccxt.__file__):
78
- raise Exception("You are running test_async.py/test.py against a globally-installed version of the library! It was previously installed into your site-packages folder by pip or pip3. To ensure testing against the local folder uninstall it first with pip uninstall ccxt or pip3 uninstall ccxt")
79
-
80
- # ------------------------------------------------------------------------------
81
-
82
- Error = Exception
83
-
84
- # # print an error string
85
- # def dump_error(*args):
86
- # string = ' '.join([str(arg) for arg in args])
87
- # print(string)
88
- # sys.stderr.write(string + "\n")
89
- # sys.stderr.flush()
90
-
91
-
92
- def handle_all_unhandled_exceptions(type, value, traceback):
93
- dump((type), (value), '\n<UNHANDLED EXCEPTION>\n' + ('\n'.join(format_tb(traceback))))
94
- exit(1) # unrecoverable crash
95
-
96
-
97
- sys.excepthook = handle_all_unhandled_exceptions
98
- # ------------------------------------------------------------------------------
99
-
100
- # non-transpiled part, but shared names among langs
101
-
102
- is_synchronous = 'async' not in os.path.basename(__file__)
103
-
104
- rootDir = DIR_NAME + '/../../../'
105
- rootDirForSkips = DIR_NAME + '/../../../'
106
- envVars = os.environ
107
- LOG_CHARS_LENGTH = 10000
108
- ext = 'py'
109
- proxyTestFileName = 'proxies'
110
-
111
-
112
- def get_cli_arg_value(arg):
113
- arg_exists = getattr(argv, arg) if hasattr(argv, arg) else False
114
- with_hyphen = '--' + arg
115
- arg_exists_with_hyphen = getattr(argv, with_hyphen) if hasattr(argv, with_hyphen) else False
116
- without_hyphen = arg.replace('--', '')
117
- arg_exists_wo_hyphen = getattr(argv, without_hyphen) if hasattr(argv, without_hyphen) else False
118
- return arg_exists or arg_exists_with_hyphen or arg_exists_wo_hyphen
119
-
120
- isWsTests = get_cli_arg_value('--ws')
121
-
3
+ from tests_helpers import AuthenticationError, NotSupported, InvalidProxySettings, ExchangeNotAvailable, OperationFailed, OnMaintenance, get_cli_arg_value, get_root_dir, is_sync, dump, json_parse, json_stringify, convert_ascii, io_file_exists, io_file_read, io_dir_read, call_method, call_method_sync, call_exchange_method_dynamically, call_exchange_method_dynamically_sync, get_root_exception, exception_message, exit_script, get_exchange_prop, set_exchange_prop, init_exchange, get_test_files_sync, get_test_files, set_fetch_response, is_null_value, close, get_env_vars, get_lang, get_ext # noqa: F401
122
4
 
123
- class baseMainTestClass():
124
- lang = 'PY'
125
- is_synchronous = is_synchronous
5
+ class testMainClass:
6
+ id_tests = False
126
7
  request_tests_failed = False
127
8
  response_tests_failed = False
128
- response_tests = False
9
+ request_tests = False
129
10
  ws_tests = False
11
+ response_tests = False
12
+ static_tests = False
13
+ info = False
14
+ verbose = False
15
+ debug = False
16
+ private_test = False
17
+ private_test_only = False
130
18
  load_keys = False
19
+ sandbox = False
20
+ only_specific_tests = []
21
+ skipped_settings_for_exchange = {}
131
22
  skipped_methods = {}
132
- check_public_tests = {}
23
+ checked_public_tests = {}
133
24
  test_files = {}
134
25
  public_tests = {}
135
- new_line = '\n'
136
- root_dir = rootDir
137
- env_vars = envVars
138
- ext = ext
139
- root_dir_for_skips = rootDirForSkips
140
- only_specific_tests = []
141
- proxy_test_file_name = proxyTestFileName
142
- pass
143
-
144
-
145
- def dump(*args):
146
- print(' '.join([str(arg) for arg in args]))
147
-
148
-
149
- def convert_ascii(str):
150
- return str # stub
151
-
152
- def json_parse(elem):
153
- return json.loads(elem)
154
-
155
-
156
- def json_stringify(elem):
157
- return json.dumps(elem)
158
-
159
-
160
- def convert_to_snake_case(content):
161
- res = re.sub(r'(?<!^)(?=[A-Z])', '_', content).lower()
162
- return res.replace('o_h_l_c_v', 'ohlcv')
163
-
164
-
165
- def get_test_name(methodName):
166
- # stub
167
- return methodName
168
-
169
-
170
- def io_file_exists(path):
171
- return os.path.isfile(path)
172
-
173
-
174
- def io_file_read(path, decode=True):
175
- fs = open(path, "r", encoding="utf-8")
176
- content = fs.read()
177
- if decode:
178
- return json.loads(content)
179
- else:
180
- return content
181
-
26
+ ext = ''
27
+ lang = ''
28
+ proxy_test_file_name = 'proxies'
182
29
 
183
- def io_dir_read(path):
184
- return os.listdir(path)
185
-
186
-
187
- def call_method(test_files, methodName, exchange, skippedProperties, args):
188
- methodNameToCall = 'test_' + convert_to_snake_case(methodName)
189
- return getattr(test_files[methodName], methodNameToCall)(exchange, skippedProperties, *args)
190
-
191
-
192
- def call_exchange_method_dynamically(exchange, methodName, args):
193
- return getattr(exchange, methodName)(*args)
194
-
195
- def call_overriden_method(exchange, methodName, args):
196
- # needed for php
197
- return call_exchange_method_dynamically(exchange, methodName, args)
198
-
199
- def exception_message(exc):
200
- message = '[' + type(exc).__name__ + '] ' + "".join(format_exception(type(exc), exc, exc.__traceback__, limit=6))
201
- if len(message) > LOG_CHARS_LENGTH:
202
- # Accessing out of range element causes error
203
- message = message[0:LOG_CHARS_LENGTH]
204
- return message
205
-
206
-
207
- def exit_script(code=0):
208
- exit(code)
209
-
210
-
211
- def get_exchange_prop(exchange, prop, defaultValue=None):
212
- if hasattr(exchange, prop):
213
- res = getattr(exchange, prop)
214
- if res is not None and res != '':
215
- return res
216
- return defaultValue
217
-
218
-
219
- def set_exchange_prop(exchange, prop, value):
220
- setattr(exchange, prop, value)
221
- # set snake case too
222
- setattr(exchange, convert_to_snake_case(prop), value)
223
-
224
-
225
- def init_exchange(exchangeId, args, is_ws=False):
226
- if (is_ws):
227
- return getattr(ccxtpro, exchangeId)(args)
228
- return getattr(ccxt, exchangeId)(args)
229
-
230
-
231
- def get_test_files(properties, ws=False):
232
- tests = {}
233
- finalPropList = properties + [proxyTestFileName]
234
- for i in range(0, len(finalPropList)):
235
- methodName = finalPropList[i]
236
- name_snake_case = convert_to_snake_case(methodName)
237
- prefix = 'async' if not is_synchronous else 'sync'
238
- dir_to_test = DIR_NAME + '/' + prefix + '/'
239
- module_string = 'ccxt.test.' + prefix + '.test_' + name_snake_case
240
- if (ws):
241
- prefix = 'pro'
242
- dir_to_test = DIR_NAME + '/../' + prefix + '/test/Exchange/'
243
- module_string = 'ccxt.pro.test.Exchange.test_' + name_snake_case
244
- filePathWithExt = dir_to_test + 'test_' + name_snake_case + '.py'
245
- if (io_file_exists (filePathWithExt)):
246
- imp = importlib.import_module(module_string)
247
- tests[methodName] = imp # getattr(imp, finalName)
248
- return tests
249
-
250
- def close(exchange):
251
- if (not is_synchronous and hasattr(exchange, 'close')):
252
- exchange.close()
253
-
254
- def is_null_value(value):
255
- return value is None
256
-
257
- def set_fetch_response(exchange: ccxt.Exchange, data):
258
- def fetch(url, method='GET', headers=None, body=None):
259
- return data
260
- exchange.fetch = fetch
261
- return exchange
262
-
263
- # *********************************
264
- # ***** AUTO-TRANSPILER-START *****
265
- class testMainClass(baseMainTestClass):
266
- def parse_cli_args(self):
267
- self.response_tests = get_cli_arg_value('--responseTests')
30
+ def parse_cli_args_and_props(self):
31
+ self.response_tests = get_cli_arg_value('--responseTests') or get_cli_arg_value('--response')
268
32
  self.id_tests = get_cli_arg_value('--idTests')
269
- self.request_tests = get_cli_arg_value('--requestTests')
33
+ self.request_tests = get_cli_arg_value('--requestTests') or get_cli_arg_value('--request')
270
34
  self.info = get_cli_arg_value('--info')
271
35
  self.verbose = get_cli_arg_value('--verbose')
272
36
  self.debug = get_cli_arg_value('--debug')
@@ -275,9 +39,11 @@ class testMainClass(baseMainTestClass):
275
39
  self.sandbox = get_cli_arg_value('--sandbox')
276
40
  self.load_keys = get_cli_arg_value('--loadKeys')
277
41
  self.ws_tests = get_cli_arg_value('--ws')
42
+ self.lang = get_lang()
43
+ self.ext = get_ext()
278
44
 
279
- def init(self, exchange_id, symbol_argv):
280
- self.parse_cli_args()
45
+ def init(self, exchange_id, symbol_argv, method_argv):
46
+ self.parse_cli_args_and_props()
281
47
  if self.request_tests and self.response_tests:
282
48
  self.run_static_request_tests(exchange_id, symbol_argv)
283
49
  self.run_static_response_tests(exchange_id, symbol_argv)
@@ -291,13 +57,14 @@ class testMainClass(baseMainTestClass):
291
57
  if self.id_tests:
292
58
  self.run_broker_id_tests()
293
59
  return
294
- symbol_str = symbol_argv if symbol_argv is not None else 'all'
295
- exchange_object = {
60
+ new_line = '\n'
61
+ dump(new_line + '' + new_line + '' + '[INFO] TESTING ', self.ext, {
296
62
  'exchange': exchange_id,
297
- 'symbol': symbol_str,
63
+ 'symbol': symbol_argv,
64
+ 'method': method_argv,
298
65
  'isWs': self.ws_tests,
299
- }
300
- dump(self.new_line + '' + self.new_line + '' + '[INFO] TESTING ', self.ext, json_stringify(exchange_object), self.new_line)
66
+ 'useProxy': get_cli_arg_value('--useProxy'),
67
+ }, new_line)
301
68
  exchange_args = {
302
69
  'verbose': self.verbose,
303
70
  'debug': self.debug,
@@ -310,30 +77,30 @@ class testMainClass(baseMainTestClass):
310
77
  self.import_files(exchange)
311
78
  assert len(list(self.test_files.keys())) > 0, 'Test files were not loaded' # ensure test files are found & filled
312
79
  self.expand_settings(exchange)
313
- symbol = self.check_if_specific_test_is_chosen(symbol_argv)
314
- self.start_test(exchange, symbol)
80
+ self.check_if_specific_test_is_chosen(method_argv)
81
+ self.start_test(exchange, symbol_argv)
315
82
  exit_script(0) # needed to be explicitly finished for WS tests
316
83
 
317
- def check_if_specific_test_is_chosen(self, symbol_argv):
318
- if symbol_argv is not None:
84
+ def check_if_specific_test_is_chosen(self, method_argv):
85
+ if method_argv is not None:
319
86
  test_file_names = list(self.test_files.keys())
320
- possible_method_names = symbol_argv.split(',') # i.e. `test.ts binance fetchBalance,fetchDeposits`
87
+ possible_method_names = method_argv.split(',') # i.e. `test.ts binance fetchBalance,fetchDeposits`
321
88
  if len(possible_method_names) >= 1:
322
89
  for i in range(0, len(test_file_names)):
323
90
  test_file_name = test_file_names[i]
324
91
  for j in range(0, len(possible_method_names)):
325
92
  method_name = possible_method_names[j]
93
+ method_name = method_name.replace('()', '')
326
94
  if test_file_name == method_name:
327
95
  self.only_specific_tests.append(test_file_name)
328
- # if method names were found, then remove them from symbolArgv
329
- if len(self.only_specific_tests) > 0:
330
- return None
331
- return symbol_argv
332
96
 
333
97
  def import_files(self, exchange):
334
98
  properties = list(exchange.has.keys())
335
99
  properties.append('loadMarkets')
336
- self.test_files = get_test_files(properties, self.ws_tests)
100
+ if is_sync():
101
+ self.test_files = get_test_files_sync(properties, self.ws_tests)
102
+ else:
103
+ self.test_files = get_test_files(properties, self.ws_tests)
337
104
 
338
105
  def load_credentials_from_env(self, exchange):
339
106
  exchange_id = exchange.id
@@ -345,14 +112,15 @@ class testMainClass(baseMainTestClass):
345
112
  if is_required and get_exchange_prop(exchange, credential) is None:
346
113
  full_key = exchange_id + '_' + credential
347
114
  credential_env_name = full_key.upper() # example: KRAKEN_APIKEY
348
- credential_value = self.env_vars[credential_env_name] if (credential_env_name in self.env_vars) else None
115
+ env_vars = get_env_vars()
116
+ credential_value = env_vars[credential_env_name] if (credential_env_name in env_vars) else None
349
117
  if credential_value:
350
118
  set_exchange_prop(exchange, credential, credential_value)
351
119
 
352
120
  def expand_settings(self, exchange):
353
121
  exchange_id = exchange.id
354
- keys_global = self.root_dir + 'keys.json'
355
- keys_local = self.root_dir + 'keys.local.json'
122
+ keys_global = get_root_dir() + 'keys.json'
123
+ keys_local = get_root_dir() + 'keys.local.json'
356
124
  keys_global_exists = io_file_exists(keys_global)
357
125
  keys_local_exists = io_file_exists(keys_local)
358
126
  global_settings = io_file_read(keys_global) if keys_global_exists else {}
@@ -375,9 +143,10 @@ class testMainClass(baseMainTestClass):
375
143
  if self.load_keys:
376
144
  self.load_credentials_from_env(exchange)
377
145
  # skipped tests
378
- skipped_file = self.root_dir_for_skips + 'skip-tests.json'
146
+ skipped_file = get_root_dir() + 'skip-tests.json'
379
147
  skipped_settings = io_file_read(skipped_file)
380
- skipped_settings_for_exchange = exchange.safe_value(skipped_settings, exchange_id, {})
148
+ self.skipped_settings_for_exchange = exchange.safe_value(skipped_settings, exchange_id, {})
149
+ skipped_settings_for_exchange = self.skipped_settings_for_exchange
381
150
  # others
382
151
  timeout = exchange.safe_value(skipped_settings_for_exchange, 'timeout')
383
152
  if timeout is not None:
@@ -400,31 +169,18 @@ class testMainClass(baseMainTestClass):
400
169
  res += ' '
401
170
  return message + res
402
171
 
403
- def exchange_hint(self, exchange, market=None):
404
- market_type = exchange.safe_string_2(exchange.options, 'defaultType', 'type', '')
405
- market_sub_type = exchange.safe_string_2(exchange.options, 'defaultSubType', 'subType')
406
- if market is not None:
407
- market_type = market['type']
408
- if market['linear']:
409
- market_sub_type = 'linear'
410
- elif market['inverse']:
411
- market_sub_type = 'inverse'
412
- elif exchange.safe_value(market, 'quanto'):
413
- market_sub_type = 'quanto'
414
- is_ws = ('ws' in exchange.has)
415
- ws_flag = '(WS)' if is_ws else ''
416
- result = exchange.id + ' ' + ws_flag + ' ' + market_type
417
- if market_sub_type is not None:
418
- result = result + ' [subType: ' + market_sub_type + '] '
419
- return result
420
-
421
172
  def test_method(self, method_name, exchange, args, is_public):
173
+ # todo: temporary skip for c#
174
+ if 'OrderBook' in method_name and self.ext == 'cs':
175
+ exchange.options['checksum'] = False
422
176
  # todo: temporary skip for php
423
177
  if 'OrderBook' in method_name and self.ext == 'php':
424
178
  return
179
+ skipped_properties_for_method = self.get_skips(exchange, method_name)
425
180
  is_load_markets = (method_name == 'loadMarkets')
426
181
  is_fetch_currencies = (method_name == 'fetchCurrencies')
427
182
  is_proxy_test = (method_name == self.proxy_test_file_name)
183
+ is_feature_test = (method_name == 'features')
428
184
  # if this is a private test, and the implementation was already tested in public, then no need to re-test it in private test (exception is fetchCurrencies, because our approach in base exchange)
429
185
  if not is_public and (method_name in self.checked_public_tests) and not is_fetch_currencies:
430
186
  return
@@ -432,31 +188,46 @@ class testMainClass(baseMainTestClass):
432
188
  supported_by_exchange = (method_name in exchange.has) and exchange.has[method_name]
433
189
  if not is_load_markets and (len(self.only_specific_tests) > 0 and not exchange.in_array(method_name, self.only_specific_tests)):
434
190
  skip_message = '[INFO] IGNORED_TEST'
435
- elif not is_load_markets and not supported_by_exchange and not is_proxy_test:
191
+ elif not is_load_markets and not supported_by_exchange and not is_proxy_test and not is_feature_test:
436
192
  skip_message = '[INFO] UNSUPPORTED_TEST' # keep it aligned with the longest message
437
- elif (method_name in self.skipped_methods) and (isinstance(self.skipped_methods[method_name], str)):
193
+ elif isinstance(skipped_properties_for_method, str):
438
194
  skip_message = '[INFO] SKIPPED_TEST'
439
195
  elif not (method_name in self.test_files):
440
196
  skip_message = '[INFO] UNIMPLEMENTED_TEST'
441
197
  # exceptionally for `loadMarkets` call, we call it before it's even checked for "skip" as we need it to be called anyway (but can skip "test.loadMarket" for it)
442
198
  if is_load_markets:
443
199
  exchange.load_markets(True)
200
+ name = exchange.id
444
201
  if skip_message:
445
202
  if self.info:
446
- dump(self.add_padding(skip_message, 25), self.exchange_hint(exchange), method_name)
203
+ dump(self.add_padding(skip_message, 25), name, method_name)
447
204
  return
448
205
  if self.info:
449
- args_stringified = '(' + ','.join(args) + ')'
450
- dump(self.add_padding('[INFO] TESTING', 25), self.exchange_hint(exchange), method_name, args_stringified)
451
- call_method(self.test_files, method_name, exchange, self.get_skips(exchange, method_name), args)
452
- # if it was passed successfully, add to the list of successfull tests
206
+ args_stringified = '(' + exchange.json(args) + ')' # args.join() breaks when we provide a list of symbols or multidimensional array; "args.toString()" breaks bcz of "array to string conversion"
207
+ dump(self.add_padding('[INFO] TESTING', 25), name, method_name, args_stringified)
208
+ if is_sync():
209
+ call_method_sync(self.test_files, method_name, exchange, skipped_properties_for_method, args)
210
+ else:
211
+ call_method(self.test_files, method_name, exchange, skipped_properties_for_method, args)
212
+ if self.info:
213
+ dump(self.add_padding('[INFO] TESTING DONE', 25), name, method_name)
214
+ # add to the list of successed tests
453
215
  if is_public:
454
216
  self.checked_public_tests[method_name] = True
455
217
  return
456
218
 
457
219
  def get_skips(self, exchange, method_name):
458
- # get "method-specific" skips
459
- skips_for_method = exchange.safe_value(self.skipped_methods, method_name, {})
220
+ final_skips = {}
221
+ # check the exact method (i.e. `fetchTrades`) and language-specific (i.e. `fetchTrades.php`)
222
+ method_names = [method_name, method_name + '.' + self.ext]
223
+ for i in range(0, len(method_names)):
224
+ m_name = method_names[i]
225
+ if m_name in self.skipped_methods:
226
+ # if whole method is skipped, by assigning a string to it, i.e. "fetchOrders":"blabla"
227
+ if isinstance(self.skipped_methods[m_name], str):
228
+ return self.skipped_methods[m_name]
229
+ else:
230
+ final_skips = exchange.deep_extend(final_skips, self.skipped_methods[m_name])
460
231
  # get "object-specific" skips
461
232
  object_skips = {
462
233
  'orderBook': ['fetchOrderBook', 'fetchOrderBooks', 'fetchL2OrderBook', 'watchOrderBook', 'watchOrderBookForSymbols'],
@@ -472,9 +243,21 @@ class testMainClass(baseMainTestClass):
472
243
  object_name = object_names[i]
473
244
  object_methods = object_skips[object_name]
474
245
  if exchange.in_array(method_name, object_methods):
246
+ # if whole object is skipped, by assigning a string to it, i.e. "orderBook":"blabla"
247
+ if (object_name in self.skipped_methods) and (isinstance(self.skipped_methods[object_name], str)):
248
+ return self.skipped_methods[object_name]
475
249
  extra_skips = exchange.safe_dict(self.skipped_methods, object_name, {})
476
- return exchange.deep_extend(skips_for_method, extra_skips)
477
- return skips_for_method
250
+ final_skips = exchange.deep_extend(final_skips, extra_skips)
251
+ # extend related skips
252
+ # - if 'timestamp' is skipped, we should do so for 'datetime' too
253
+ # - if 'bid' is skipped, skip 'ask' too
254
+ if ('timestamp' in final_skips) and not ('datetime' in final_skips):
255
+ final_skips['datetime'] = final_skips['timestamp']
256
+ if ('bid' in final_skips) and not ('ask' in final_skips):
257
+ final_skips['ask'] = final_skips['bid']
258
+ if ('baseVolume' in final_skips) and not ('quoteVolume' in final_skips):
259
+ final_skips['quoteVolume'] = final_skips['baseVolume']
260
+ return final_skips
478
261
 
479
262
  def test_safe(self, method_name, exchange, args=[], is_public=False):
480
263
  # `testSafe` method does not throw an exception, instead mutes it. The reason we
@@ -483,12 +266,13 @@ class testMainClass(baseMainTestClass):
483
266
  # formatted message "[TEST_FAILURE] ..." and that output is then regex-matched by
484
267
  # run-tests.js, so the exceptions are still printed out to console from there.
485
268
  max_retries = 3
486
- args_stringified = exchange.json(args) # args.join() breaks when we provide a list of symbols | "args.toString()" breaks bcz of "array to string conversion"
269
+ args_stringified = exchange.json(args) # args.join() breaks when we provide a list of symbols or multidimensional array; "args.toString()" breaks bcz of "array to string conversion"
487
270
  for i in range(0, max_retries):
488
271
  try:
489
272
  self.test_method(method_name, exchange, args, is_public)
490
273
  return True
491
- except Exception as e:
274
+ except Exception as ex:
275
+ e = get_root_exception(ex)
492
276
  is_load_markets = (method_name == 'loadMarkets')
493
277
  is_auth_error = (isinstance(e, AuthenticationError))
494
278
  is_not_supported = (isinstance(e, NotSupported))
@@ -520,36 +304,37 @@ class testMainClass(baseMainTestClass):
520
304
  return_success = True
521
305
  # output the message
522
306
  fail_type = '[TEST_FAILURE]' if should_fail else '[TEST_WARNING]'
523
- dump(fail_type, 'Method could not be tested due to a repeated Network/Availability issues', ' | ', self.exchange_hint(exchange), method_name, args_stringified, exception_message(e))
307
+ dump(fail_type, 'Method could not be tested due to a repeated Network/Availability issues', ' | ', exchange.id, method_name, args_stringified, exception_message(e))
524
308
  return return_success
525
309
  else:
526
310
  # wait and retry again
527
311
  # (increase wait time on every retry)
528
- exchange.sleep(i * 1000)
312
+ exchange.sleep((i + 1) * 1000)
529
313
  continue
530
314
  else:
531
315
  # if it's loadMarkets, then fail test, because it's mandatory for tests
532
316
  if is_load_markets:
533
- dump('[TEST_FAILURE]', 'Exchange can not load markets', exception_message(e), self.exchange_hint(exchange), method_name, args_stringified)
317
+ dump('[TEST_FAILURE]', 'Exchange can not load markets', exception_message(e), exchange.id, method_name, args_stringified)
534
318
  return False
535
319
  # if the specific arguments to the test method throws "NotSupported" exception
536
320
  # then let's don't fail the test
537
321
  if is_not_supported:
538
322
  if self.info:
539
- dump('[INFO] NOT_SUPPORTED', exception_message(e), self.exchange_hint(exchange), method_name, args_stringified)
323
+ dump('[INFO] NOT_SUPPORTED', exception_message(e), exchange.id, method_name, args_stringified)
540
324
  return True
541
325
  # If public test faces authentication error, we don't break (see comments under `testSafe` method)
542
326
  if is_public and is_auth_error:
543
327
  if self.info:
544
- dump('[INFO]', 'Authentication problem for public method', exception_message(e), self.exchange_hint(exchange), method_name, args_stringified)
328
+ dump('[INFO]', 'Authentication problem for public method', exception_message(e), exchange.id, method_name, args_stringified)
545
329
  return True
546
330
  else:
547
- dump('[TEST_FAILURE]', exception_message(e), self.exchange_hint(exchange), method_name, args_stringified)
331
+ dump('[TEST_FAILURE]', exception_message(e), exchange.id, method_name, args_stringified)
548
332
  return False
549
333
  return True
550
334
 
551
335
  def run_public_tests(self, exchange, symbol):
552
336
  tests = {
337
+ 'features': [],
553
338
  'fetchCurrencies': [],
554
339
  'fetchTicker': [symbol],
555
340
  'fetchTickers': [symbol],
@@ -566,10 +351,14 @@ class testMainClass(baseMainTestClass):
566
351
  if self.ws_tests:
567
352
  tests = {
568
353
  'watchOHLCV': [symbol],
354
+ 'watchOHLCVForSymbols': [symbol],
569
355
  'watchTicker': [symbol],
570
356
  'watchTickers': [symbol],
357
+ 'watchBidsAsks': [symbol],
571
358
  'watchOrderBook': [symbol],
359
+ 'watchOrderBookForSymbols': [[symbol]],
572
360
  'watchTrades': [symbol],
361
+ 'watchTradesForSymbols': [[symbol]],
573
362
  }
574
363
  market = exchange.market(symbol)
575
364
  is_spot = market['spot']
@@ -606,34 +395,26 @@ class testMainClass(baseMainTestClass):
606
395
  test_prefix_string = 'PUBLIC_TESTS' if is_public_test else 'PRIVATE_TESTS'
607
396
  if len(failed_methods):
608
397
  errors_string = ', '.join(failed_methods)
609
- dump('[TEST_FAILURE]', self.exchange_hint(exchange), test_prefix_string, 'Failed methods : ' + errors_string)
398
+ dump('[TEST_FAILURE]', exchange.id, test_prefix_string, 'Failed methods : ' + errors_string)
610
399
  if self.info:
611
- dump(self.add_padding('[INFO] END ' + test_prefix_string + ' ' + self.exchange_hint(exchange), 25))
400
+ dump(self.add_padding('[INFO] END ' + test_prefix_string + ' ' + exchange.id, 25))
612
401
 
613
402
  def load_exchange(self, exchange):
614
403
  result = self.test_safe('loadMarkets', exchange, [], True)
615
404
  if not result:
616
405
  return False
617
- symbols = ['BTC/USDT', 'BTC/USDC', 'BTC/CNY', 'BTC/USD', 'BTC/EUR', 'BTC/ETH', 'ETH/BTC', 'BTC/JPY', 'ETH/EUR', 'ETH/JPY', 'ETH/CNY', 'ETH/USD', 'LTC/CNY', 'DASH/BTC', 'DOGE/BTC', 'BTC/AUD', 'BTC/PLN', 'USD/SLL', 'BTC/RUB', 'BTC/UAH', 'LTC/BTC', 'EUR/USD']
618
- result_symbols = []
619
- exchange_specific_symbols = exchange.symbols
620
- for i in range(0, len(exchange_specific_symbols)):
621
- symbol = exchange_specific_symbols[i]
622
- if exchange.in_array(symbol, symbols):
623
- result_symbols.append(symbol)
624
- result_msg = ''
625
- result_length = len(result_symbols)
626
406
  exchange_symbols_length = len(exchange.symbols)
627
- if result_length > 0:
628
- if exchange_symbols_length > result_length:
629
- result_msg = ', '.join(result_symbols) + ' + more...'
630
- else:
631
- result_msg = ', '.join(result_symbols)
632
- dump('[INFO:MAIN] Exchange loaded', exchange_symbols_length, 'symbols', result_msg)
407
+ dump('[INFO:MAIN] Exchange loaded', exchange_symbols_length, 'symbols')
633
408
  return True
634
409
 
635
410
  def get_test_symbol(self, exchange, is_spot, symbols):
636
411
  symbol = None
412
+ preferred_spot_symbol = exchange.safe_string(self.skipped_settings_for_exchange, 'preferredSpotSymbol')
413
+ preferred_swap_symbol = exchange.safe_string(self.skipped_settings_for_exchange, 'preferredSwapSymbol')
414
+ if is_spot and preferred_spot_symbol:
415
+ return preferred_spot_symbol
416
+ elif not is_spot and preferred_swap_symbol:
417
+ return preferred_swap_symbol
637
418
  for i in range(0, len(symbols)):
638
419
  s = symbols[i]
639
420
  market = exchange.safe_value(exchange.markets, s)
@@ -668,9 +449,9 @@ class testMainClass(baseMainTestClass):
668
449
 
669
450
  def get_valid_symbol(self, exchange, spot=True):
670
451
  current_type_markets = self.get_markets_from_exchange(exchange, spot)
671
- codes = ['BTC', 'ETH', 'XRP', 'LTC', 'BCH', 'EOS', 'BNB', 'BSV', 'USDT', 'ATOM', 'BAT', 'BTG', 'DASH', 'DOGE', 'ETC', 'IOTA', 'LSK', 'MKR', 'NEO', 'PAX', 'QTUM', 'TRX', 'TUSD', 'USD', 'USDC', 'WAVES', 'XEM', 'XMR', 'ZEC', 'ZRX']
672
- spot_symbols = ['BTC/USDT', 'BTC/USDC', 'BTC/USD', 'BTC/CNY', 'BTC/EUR', 'BTC/ETH', 'ETH/BTC', 'ETH/USD', 'ETH/USDT', 'BTC/JPY', 'LTC/BTC', 'ZRX/WETH', 'EUR/USD']
673
- swap_symbols = ['BTC/USDT:USDT', 'BTC/USDC:USDC', 'BTC/USD:USD', 'ETH/USDT:USDT', 'ETH/USD:USD', 'LTC/USDT:USDT', 'DOGE/USDT:USDT', 'ADA/USDT:USDT', 'BTC/USD:BTC', 'ETH/USD:ETH']
452
+ codes = ['BTC', 'ETH', 'XRP', 'LTC', 'BNB', 'DASH', 'DOGE', 'ETC', 'TRX', 'USDT', 'USDC', 'USD', 'EUR', 'TUSD', 'CNY', 'JPY', 'BRL']
453
+ spot_symbols = ['BTC/USDT', 'BTC/USDC', 'BTC/USD', 'BTC/CNY', 'BTC/EUR', 'BTC/AUD', 'BTC/BRL', 'BTC/JPY', 'ETH/USDT', 'ETH/USDC', 'ETH/USD', 'ETH/CNY', 'ETH/EUR', 'ETH/AUD', 'ETH/BRL', 'ETH/JPY', 'EUR/USDT', 'EUR/USD', 'EUR/USDC', 'USDT/EUR', 'USD/EUR', 'USDC/EUR', 'BTC/ETH', 'ETH/BTC']
454
+ swap_symbols = ['BTC/USDT:USDT', 'BTC/USDC:USDC', 'BTC/USD:USD', 'ETH/USDT:USDT', 'ETH/USDC:USDC', 'ETH/USD:USD', 'BTC/USD:BTC', 'ETH/USD:ETH']
674
455
  target_symbols = spot_symbols if spot else swap_symbols
675
456
  symbol = self.get_test_symbol(exchange, spot, target_symbols)
676
457
  # if symbols wasn't found from above hardcoded list, then try to locate any symbol which has our target hardcoded 'base' code
@@ -778,6 +559,8 @@ class testMainClass(baseMainTestClass):
778
559
  'fetchBorrowRateHistory': [code],
779
560
  'fetchLedgerEntry': [code],
780
561
  }
562
+ if get_cli_arg_value('--fundedTests'):
563
+ tests['createOrder'] = [symbol]
781
564
  if self.ws_tests:
782
565
  tests = {
783
566
  'watchBalance': [code],
@@ -808,7 +591,7 @@ class testMainClass(baseMainTestClass):
808
591
  # these tests should be synchronously executed, because of conflicting nature of proxy settings
809
592
  proxy_test_name = self.proxy_test_file_name
810
593
  # todo: temporary skip for sync py
811
- if self.ext == 'py' and self.is_synchronous:
594
+ if self.ext == 'py' and is_sync():
812
595
  return
813
596
  # try proxy several times
814
597
  max_retries = 3
@@ -816,12 +599,16 @@ class testMainClass(baseMainTestClass):
816
599
  for j in range(0, max_retries):
817
600
  try:
818
601
  self.test_method(proxy_test_name, exchange, [], True)
819
- break # if successfull, then break
602
+ return # if successfull, then end the test
820
603
  except Exception as e:
821
604
  exception = e
605
+ exchange.sleep(j * 1000)
822
606
  # if exception was set, then throw it
823
- if exception:
607
+ if exception is not None:
824
608
  error_message = '[TEST_FAILURE] Failed ' + proxy_test_name + ' : ' + exception_message(exception)
609
+ # temporary comment the below, because c# transpilation failure
610
+ # throw new Exchange Error (errorMessage.toString ());
611
+ dump('[TEST_WARNING]' + str(error_message))
825
612
 
826
613
  def start_test(self, exchange, symbol):
827
614
  # we do not need to test aliases
@@ -832,16 +619,19 @@ class testMainClass(baseMainTestClass):
832
619
  try:
833
620
  result = self.load_exchange(exchange)
834
621
  if not result:
835
- close(exchange)
622
+ if not is_sync():
623
+ close(exchange)
836
624
  return
837
625
  # if (exchange.id === 'binance') {
838
626
  # # we test proxies functionality just for one random exchange on each build, because proxy functionality is not exchange-specific, instead it's all done from base methods, so just one working sample would mean it works for all ccxt exchanges
839
627
  # # this.testProxies (exchange);
840
628
  # }
841
629
  self.test_exchange(exchange, symbol)
842
- close(exchange)
630
+ if not is_sync():
631
+ close(exchange)
843
632
  except Exception as e:
844
- close(exchange)
633
+ if not is_sync():
634
+ close(exchange)
845
635
  raise e
846
636
 
847
637
  def assert_static_error(self, cond, message, calculated_output, stored_output, key=None):
@@ -850,9 +640,10 @@ class testMainClass(baseMainTestClass):
850
640
  # -----------------------------------------------------------------------------
851
641
  calculated_string = json_stringify(calculated_output)
852
642
  stored_string = json_stringify(stored_output)
853
- error_message = message + ' computed ' + stored_string + ' stored: ' + calculated_string
643
+ error_message = message
854
644
  if key is not None:
855
- error_message = ' | ' + key + ' | ' + 'computed value: ' + stored_string + ' stored value: ' + calculated_string
645
+ error_message = '[' + key + ']'
646
+ error_message += ' computed: ' + stored_string + ' stored: ' + calculated_string
856
647
  assert cond, error_message
857
648
 
858
649
  def load_markets_from_file(self, id):
@@ -860,12 +651,12 @@ class testMainClass(baseMainTestClass):
860
651
  # to make this test as fast as possible
861
652
  # and basically independent from the exchange
862
653
  # so we can run it offline
863
- filename = self.root_dir + './ts/src/test/static/markets/' + id + '.json'
654
+ filename = get_root_dir() + './ts/src/test/static/markets/' + id + '.json'
864
655
  content = io_file_read(filename)
865
656
  return content
866
657
 
867
658
  def load_currencies_from_file(self, id):
868
- filename = self.root_dir + './ts/src/test/static/currencies/' + id + '.json'
659
+ filename = get_root_dir() + './ts/src/test/static/currencies/' + id + '.json'
869
660
  content = io_file_read(filename)
870
661
  return content
871
662
 
@@ -922,7 +713,7 @@ class testMainClass(baseMainTestClass):
922
713
  result[key] = value
923
714
  return result
924
715
 
925
- def assert_new_and_stored_output(self, exchange, skip_keys, new_output, stored_output, strict_type_check=True, asserting_key=None):
716
+ def assert_new_and_stored_output_inner(self, exchange, skip_keys, new_output, stored_output, strict_type_check=True, asserting_key=None):
926
717
  if is_null_value(new_output) and is_null_value(stored_output):
927
718
  return True
928
719
  if not new_output and not stored_output:
@@ -963,9 +754,17 @@ class testMainClass(baseMainTestClass):
963
754
  # when comparing the response we want to allow some flexibility, because a 50.0 can be equal to 50 after saving it to the json file
964
755
  self.assert_static_error(sanitized_new_output == sanitized_stored_output, message_error, stored_output, new_output, asserting_key)
965
756
  else:
966
- is_boolean = (isinstance(sanitized_new_output, bool)) or (isinstance(sanitized_stored_output, bool))
967
- is_string = (isinstance(sanitized_new_output, str)) or (isinstance(sanitized_stored_output, str))
968
- is_undefined = (sanitized_new_output is None) or (sanitized_stored_output is None) # undefined is a perfetly valid value
757
+ is_computed_bool = (isinstance(sanitized_new_output, bool))
758
+ is_stored_bool = (isinstance(sanitized_stored_output, bool))
759
+ is_computed_string = (isinstance(sanitized_new_output, str))
760
+ is_stored_string = (isinstance(sanitized_stored_output, str))
761
+ is_computed_undefined = (sanitized_new_output is None)
762
+ is_stored_undefined = (sanitized_stored_output is None)
763
+ should_be_same = (is_computed_bool == is_stored_bool) and (is_computed_string == is_stored_string) and (is_computed_undefined == is_stored_undefined)
764
+ self.assert_static_error(should_be_same, 'output type mismatch', stored_output, new_output, asserting_key)
765
+ is_boolean = is_computed_bool or is_stored_bool
766
+ is_string = is_computed_string or is_stored_string
767
+ is_undefined = is_computed_undefined or is_stored_undefined # undefined is a perfetly valid value
969
768
  if is_boolean or is_string or is_undefined:
970
769
  if self.lang == 'C#':
971
770
  # tmp c# number comparsion
@@ -996,6 +795,25 @@ class testMainClass(baseMainTestClass):
996
795
  self.assert_static_error(numeric_new_output == numeric_stored_output, message_error, stored_output, new_output, asserting_key)
997
796
  return True # c# requ
998
797
 
798
+ def assert_new_and_stored_output(self, exchange, skip_keys, new_output, stored_output, strict_type_check=True, asserting_key=None):
799
+ try:
800
+ return self.assert_new_and_stored_output_inner(exchange, skip_keys, new_output, stored_output, strict_type_check, asserting_key)
801
+ except Exception as e:
802
+ if self.info:
803
+ error_message = self.var_to_string(new_output) + '(calculated)' + ' != ' + self.var_to_string(stored_output) + '(stored)'
804
+ dump('[TEST_FAILURE_DETAIL]' + error_message)
805
+ raise e
806
+
807
+ def var_to_string(self, obj=None):
808
+ new_string = None
809
+ if obj is None:
810
+ new_string = 'undefined'
811
+ elif is_null_value(obj):
812
+ new_string = 'null'
813
+ else:
814
+ new_string = json_stringify(obj)
815
+ return new_string
816
+
999
817
  def assert_static_request_output(self, exchange, type, skip_keys, stored_url, request_url, stored_output, new_output):
1000
818
  if stored_url != request_url:
1001
819
  # remove the host part from the url
@@ -1051,13 +869,16 @@ class testMainClass(baseMainTestClass):
1051
869
  new_input.append(current)
1052
870
  return new_input
1053
871
 
1054
- def test_method_statically(self, exchange, method, data, type, skip_keys):
872
+ def test_request_statically(self, exchange, method, data, type, skip_keys):
1055
873
  output = None
1056
874
  request_url = None
1057
875
  try:
1058
- call_exchange_method_dynamically(exchange, method, self.sanitize_data_input(data['input']))
876
+ if not is_sync():
877
+ call_exchange_method_dynamically(exchange, method, self.sanitize_data_input(data['input']))
878
+ else:
879
+ call_exchange_method_dynamically_sync(exchange, method, self.sanitize_data_input(data['input']))
1059
880
  except Exception as e:
1060
- if not (isinstance(e, ProxyError)):
881
+ if not (isinstance(e, InvalidProxySettings)):
1061
882
  raise e
1062
883
  output = exchange.last_request_body
1063
884
  request_url = exchange.last_request_url
@@ -1066,18 +887,22 @@ class testMainClass(baseMainTestClass):
1066
887
  self.assert_static_request_output(exchange, type, skip_keys, data['url'], request_url, call_output, output)
1067
888
  except Exception as e:
1068
889
  self.request_tests_failed = True
1069
- error_message = '[' + self.lang + '][STATIC_REQUEST_TEST_FAILURE]' + '[' + self.exchange_hint(exchange) + ']' + '[' + method + ']' + '[' + data['description'] + ']' + str(e)
890
+ error_message = '[' + self.lang + '][STATIC_REQUEST]' + '[' + exchange.id + ']' + '[' + method + ']' + '[' + data['description'] + ']' + str(e)
1070
891
  dump('[TEST_FAILURE]' + error_message)
1071
892
 
1072
893
  def test_response_statically(self, exchange, method, skip_keys, data):
1073
894
  expected_result = exchange.safe_value(data, 'parsedResponse')
1074
895
  mocked_exchange = set_fetch_response(exchange, data['httpResponse'])
1075
896
  try:
1076
- unified_result = call_exchange_method_dynamically(exchange, method, self.sanitize_data_input(data['input']))
1077
- self.assert_static_response_output(mocked_exchange, skip_keys, unified_result, expected_result)
897
+ if not is_sync():
898
+ unified_result = call_exchange_method_dynamically(exchange, method, self.sanitize_data_input(data['input']))
899
+ self.assert_static_response_output(mocked_exchange, skip_keys, unified_result, expected_result)
900
+ else:
901
+ unified_result_sync = call_exchange_method_dynamically_sync(exchange, method, self.sanitize_data_input(data['input']))
902
+ self.assert_static_response_output(mocked_exchange, skip_keys, unified_result_sync, expected_result)
1078
903
  except Exception as e:
1079
- self.request_tests_failed = True
1080
- error_message = '[' + self.lang + '][STATIC_RESPONSE_TEST_FAILURE]' + '[' + self.exchange_hint(exchange) + ']' + '[' + method + ']' + '[' + data['description'] + ']' + str(e)
904
+ self.response_tests_failed = True
905
+ error_message = '[' + self.lang + '][STATIC_RESPONSE]' + '[' + exchange.id + ']' + '[' + method + ']' + '[' + data['description'] + ']' + str(e)
1081
906
  dump('[TEST_FAILURE]' + error_message)
1082
907
  set_fetch_response(exchange, None) # reset state
1083
908
 
@@ -1098,6 +923,8 @@ class testMainClass(baseMainTestClass):
1098
923
  'privateKey': '0xff3bdd43534543d421f05aec535965b5050ad6ac15345435345435453495e771',
1099
924
  'uid': 'uid',
1100
925
  'token': 'token',
926
+ 'login': 'login',
927
+ 'accountId': 'accountId',
1101
928
  'accounts': [{
1102
929
  'id': 'myAccount',
1103
930
  'code': 'USDT',
@@ -1120,7 +947,24 @@ class testMainClass(baseMainTestClass):
1120
947
  # instantiate the exchange and make sure that we sink the requests to avoid an actual request
1121
948
  exchange = self.init_offline_exchange(exchange_name)
1122
949
  global_options = exchange.safe_dict(exchange_data, 'options', {})
1123
- exchange.options = exchange.deep_extend(exchange.options, global_options) # custom options to be used in the tests
950
+ # read apiKey/secret from the test file
951
+ api_key = exchange.safe_string(exchange_data, 'apiKey')
952
+ if api_key:
953
+ exchange.apiKey = str(api_key)
954
+ secret = exchange.safe_string(exchange_data, 'secret')
955
+ if secret:
956
+ exchange.secret = str(secret)
957
+ private_key = exchange.safe_string(exchange_data, 'privateKey')
958
+ if private_key:
959
+ exchange.privateKey = str(private_key)
960
+ wallet_address = exchange.safe_string(exchange_data, 'walletAddress')
961
+ if wallet_address:
962
+ exchange.walletAddress = str(wallet_address)
963
+ accounts = exchange.safe_list(exchange_data, 'accounts')
964
+ if accounts:
965
+ exchange.accounts = accounts
966
+ # exchange.options = exchange.deepExtend (exchange.options, globalOptions); # custom options to be used in the tests
967
+ exchange.extend_exchange_options(global_options)
1124
968
  methods = exchange.safe_value(exchange_data, 'methods', {})
1125
969
  methods_names = list(methods.keys())
1126
970
  for i in range(0, len(methods_names)):
@@ -1130,26 +974,49 @@ class testMainClass(baseMainTestClass):
1130
974
  result = results[j]
1131
975
  old_exchange_options = exchange.options # snapshot options;
1132
976
  test_exchange_options = exchange.safe_value(result, 'options', {})
1133
- exchange.options = exchange.deep_extend(old_exchange_options, test_exchange_options) # custom options to be used in the tests
977
+ # exchange.options = exchange.deepExtend (oldExchangeOptions, testExchangeOptions); # custom options to be used in the tests
978
+ exchange.extend_exchange_options(exchange.deep_extend(old_exchange_options, test_exchange_options))
1134
979
  description = exchange.safe_value(result, 'description')
1135
980
  if (test_name is not None) and (test_name != description):
1136
981
  continue
1137
982
  is_disabled = exchange.safe_bool(result, 'disabled', False)
1138
983
  if is_disabled:
1139
984
  continue
985
+ disabled_string = exchange.safe_string(result, 'disabled', '')
986
+ if disabled_string != '':
987
+ continue
988
+ is_disabled_c_sharp = exchange.safe_bool(result, 'disabledCS', False)
989
+ if is_disabled_c_sharp and (self.lang == 'C#'):
990
+ continue
1140
991
  type = exchange.safe_string(exchange_data, 'outputType')
1141
992
  skip_keys = exchange.safe_value(exchange_data, 'skipKeys', [])
1142
- self.test_method_statically(exchange, method, result, type, skip_keys)
993
+ self.test_request_statically(exchange, method, result, type, skip_keys)
1143
994
  # reset options
1144
- exchange.options = exchange.deep_extend(old_exchange_options, {})
1145
- close(exchange)
995
+ # exchange.options = exchange.deepExtend (oldExchangeOptions, {});
996
+ exchange.extend_exchange_options(exchange.deep_extend(old_exchange_options, {}))
997
+ if not is_sync():
998
+ close(exchange)
1146
999
  return True # in c# methods that will be used with promiseAll need to return something
1147
1000
 
1148
1001
  def test_exchange_response_statically(self, exchange_name, exchange_data, test_name=None):
1149
1002
  exchange = self.init_offline_exchange(exchange_name)
1003
+ # read apiKey/secret from the test file
1004
+ api_key = exchange.safe_string(exchange_data, 'apiKey')
1005
+ if api_key:
1006
+ exchange.apiKey = str(api_key)
1007
+ secret = exchange.safe_string(exchange_data, 'secret')
1008
+ if secret:
1009
+ exchange.secret = str(secret)
1010
+ private_key = exchange.safe_string(exchange_data, 'privateKey')
1011
+ if private_key:
1012
+ exchange.privateKey = str(private_key)
1013
+ wallet_address = exchange.safe_string(exchange_data, 'walletAddress')
1014
+ if wallet_address:
1015
+ exchange.walletAddress = str(wallet_address)
1150
1016
  methods = exchange.safe_value(exchange_data, 'methods', {})
1151
1017
  options = exchange.safe_value(exchange_data, 'options', {})
1152
- exchange.options = exchange.deep_extend(exchange.options, options) # custom options to be used in the tests
1018
+ # exchange.options = exchange.deepExtend (exchange.options, options); # custom options to be used in the tests
1019
+ exchange.extend_exchange_options(options)
1153
1020
  methods_names = list(methods.keys())
1154
1021
  for i in range(0, len(methods_names)):
1155
1022
  method = methods_names[i]
@@ -1159,7 +1026,8 @@ class testMainClass(baseMainTestClass):
1159
1026
  description = exchange.safe_value(result, 'description')
1160
1027
  old_exchange_options = exchange.options # snapshot options;
1161
1028
  test_exchange_options = exchange.safe_value(result, 'options', {})
1162
- exchange.options = exchange.deep_extend(old_exchange_options, test_exchange_options) # custom options to be used in the tests
1029
+ # exchange.options = exchange.deepExtend (oldExchangeOptions, testExchangeOptions); # custom options to be used in the tests
1030
+ exchange.extend_exchange_options(exchange.deep_extend(old_exchange_options, test_exchange_options))
1163
1031
  is_disabled = exchange.safe_bool(result, 'disabled', False)
1164
1032
  if is_disabled:
1165
1033
  continue
@@ -1174,8 +1042,10 @@ class testMainClass(baseMainTestClass):
1174
1042
  skip_keys = exchange.safe_value(exchange_data, 'skipKeys', [])
1175
1043
  self.test_response_statically(exchange, method, skip_keys, result)
1176
1044
  # reset options
1177
- exchange.options = exchange.deep_extend(old_exchange_options, {})
1178
- close(exchange)
1045
+ # exchange.options = exchange.deepExtend (oldExchangeOptions, {});
1046
+ exchange.extend_exchange_options(exchange.deep_extend(old_exchange_options, {}))
1047
+ if not is_sync():
1048
+ close(exchange)
1179
1049
  return True # in c# methods that will be used with promiseAll need to return something
1180
1050
 
1181
1051
  def get_number_of_tests_from_exchange(self, exchange, exchange_data, test_name=None):
@@ -1195,7 +1065,7 @@ class testMainClass(baseMainTestClass):
1195
1065
  self.run_static_tests('request', target_exchange, test_name)
1196
1066
 
1197
1067
  def run_static_tests(self, type, target_exchange=None, test_name=None):
1198
- folder = self.root_dir + './ts/src/test/static/' + type + '/'
1068
+ folder = get_root_dir() + './ts/src/test/static/' + type + '/'
1199
1069
  static_data = self.load_static_data(folder, target_exchange)
1200
1070
  if static_data is None:
1201
1071
  return
@@ -1216,11 +1086,20 @@ class testMainClass(baseMainTestClass):
1216
1086
  promises.append(self.test_exchange_request_statically(exchange_name, exchange_data, test_name))
1217
1087
  else:
1218
1088
  promises.append(self.test_exchange_response_statically(exchange_name, exchange_data, test_name))
1219
- (promises)
1089
+ try:
1090
+ (promises)
1091
+ except Exception as e:
1092
+ if type == 'request':
1093
+ self.request_tests_failed = True
1094
+ else:
1095
+ self.response_tests_failed = True
1096
+ error_message = '[' + self.lang + '][STATIC_REQUEST]' + str(e)
1097
+ dump('[TEST_FAILURE]' + error_message)
1220
1098
  if self.request_tests_failed or self.response_tests_failed:
1221
1099
  exit_script(1)
1222
1100
  else:
1223
- success_message = '[' + self.lang + '][TEST_SUCCESS] ' + str(sum) + ' static ' + type + ' tests passed.'
1101
+ prefix = '[SYNC]' if (is_sync()) else ''
1102
+ success_message = '[' + self.lang + ']' + prefix + '[TEST_SUCCESS] ' + str(sum) + ' static ' + type + ' tests passed.'
1224
1103
  dump('[INFO]' + success_message)
1225
1104
 
1226
1105
  def run_static_response_tests(self, exchange_name=None, test=None):
@@ -1233,7 +1112,7 @@ class testMainClass(baseMainTestClass):
1233
1112
  # -----------------------------------------------------------------------------
1234
1113
  # --- Init of brokerId tests functions-----------------------------------------
1235
1114
  # -----------------------------------------------------------------------------
1236
- promises = [self.test_binance(), self.test_okx(), self.test_cryptocom(), self.test_bybit(), self.test_kucoin(), self.test_kucoinfutures(), self.test_bitget(), self.test_mexc(), self.test_htx(), self.test_woo(), self.test_bitmart(), self.test_coinex(), self.test_bingx(), self.test_phemex(), self.test_blofin(), self.test_hyperliquid(), self.test_coinbaseinternational()]
1115
+ promises = [self.test_binance(), self.test_okx(), self.test_cryptocom(), self.test_bybit(), self.test_kucoin(), self.test_kucoinfutures(), self.test_bitget(), self.test_mexc(), self.test_htx(), self.test_woo(), self.test_bitmart(), self.test_coinex(), self.test_bingx(), self.test_phemex(), self.test_blofin(), self.test_hyperliquid(), self.test_coinbaseinternational(), self.test_coinbase_advanced(), self.test_woofi_pro(), self.test_oxfun(), self.test_xt(), self.test_vertex(), self.test_paradex(), self.test_hashkey(), self.test_coincatch(), self.test_defx()]
1237
1116
  (promises)
1238
1117
  success_message = '[' + self.lang + '][TEST_SUCCESS] brokerId tests passed.'
1239
1118
  dump('[INFO]' + success_message)
@@ -1266,7 +1145,8 @@ class testMainClass(baseMainTestClass):
1266
1145
  assert client_order_id_swap.startswith(swap_id_string), 'binance - swap clientOrderId: ' + client_order_id_swap + ' does not start with swapId' + swap_id_string
1267
1146
  client_order_id_inverse = swap_inverse_order_request['newClientOrderId']
1268
1147
  assert client_order_id_inverse.startswith(swap_id_string), 'binance - swap clientOrderIdInverse: ' + client_order_id_inverse + ' does not start with swapId' + swap_id_string
1269
- close(exchange)
1148
+ if not is_sync():
1149
+ close(exchange)
1270
1150
  return True
1271
1151
 
1272
1152
  def test_okx(self):
@@ -1291,7 +1171,8 @@ class testMainClass(baseMainTestClass):
1291
1171
  assert client_order_id_swap.startswith(id_string), 'okx - swap clientOrderId: ' + client_order_id_swap + ' does not start with id: ' + id_string
1292
1172
  swap_tag = swap_order_request[0]['tag']
1293
1173
  assert swap_tag == id, 'okx - id: ' + id + ' different from swap tag: ' + swap_tag
1294
- close(exchange)
1174
+ if not is_sync():
1175
+ close(exchange)
1295
1176
  return True
1296
1177
 
1297
1178
  def test_cryptocom(self):
@@ -1305,7 +1186,8 @@ class testMainClass(baseMainTestClass):
1305
1186
  request = json_parse(exchange.last_request_body)
1306
1187
  broker_id = request['params']['broker_id']
1307
1188
  assert broker_id == id, 'cryptocom - id: ' + id + ' different from broker_id: ' + broker_id
1308
- close(exchange)
1189
+ if not is_sync():
1190
+ close(exchange)
1309
1191
  return True
1310
1192
 
1311
1193
  def test_bybit(self):
@@ -1319,17 +1201,17 @@ class testMainClass(baseMainTestClass):
1319
1201
  # we expect an error here, we're only interested in the headers
1320
1202
  req_headers = exchange.last_request_headers
1321
1203
  assert req_headers['Referer'] == id, 'bybit - id: ' + id + ' not in headers.'
1322
- close(exchange)
1204
+ if not is_sync():
1205
+ close(exchange)
1323
1206
  return True
1324
1207
 
1325
1208
  def test_kucoin(self):
1326
1209
  exchange = self.init_offline_exchange('kucoin')
1327
1210
  req_headers = None
1328
- options_string = str(exchange.options)
1329
1211
  spot_id = exchange.options['partner']['spot']['id']
1330
1212
  spot_key = exchange.options['partner']['spot']['key']
1331
- assert spot_id == 'ccxt', 'kucoin - id: ' + spot_id + ' not in options: ' + options_string
1332
- assert spot_key == '9e58cc35-5b5e-4133-92ec-166e3f077cb8', 'kucoin - key: ' + spot_key + ' not in options: ' + options_string
1213
+ assert spot_id == 'ccxt', 'kucoin - id: ' + spot_id + ' not in options'
1214
+ assert spot_key == '9e58cc35-5b5e-4133-92ec-166e3f077cb8', 'kucoin - key: ' + spot_key + ' not in options.'
1333
1215
  try:
1334
1216
  exchange.create_order('BTC/USDT', 'limit', 'buy', 1, 20000)
1335
1217
  except Exception as e:
@@ -1337,54 +1219,54 @@ class testMainClass(baseMainTestClass):
1337
1219
  req_headers = exchange.last_request_headers
1338
1220
  id = 'ccxt'
1339
1221
  assert req_headers['KC-API-PARTNER'] == id, 'kucoin - id: ' + id + ' not in headers.'
1340
- close(exchange)
1222
+ if not is_sync():
1223
+ close(exchange)
1341
1224
  return True
1342
1225
 
1343
1226
  def test_kucoinfutures(self):
1344
1227
  exchange = self.init_offline_exchange('kucoinfutures')
1345
1228
  req_headers = None
1346
1229
  id = 'ccxtfutures'
1347
- options_string = str(exchange.options['partner']['future'])
1348
1230
  future_id = exchange.options['partner']['future']['id']
1349
1231
  future_key = exchange.options['partner']['future']['key']
1350
- assert future_id == id, 'kucoinfutures - id: ' + future_id + ' not in options: ' + options_string
1351
- assert future_key == '1b327198-f30c-4f14-a0ac-918871282f15', 'kucoinfutures - key: ' + future_key + ' not in options: ' + options_string
1232
+ assert future_id == id, 'kucoinfutures - id: ' + future_id + ' not in options.'
1233
+ assert future_key == '1b327198-f30c-4f14-a0ac-918871282f15', 'kucoinfutures - key: ' + future_key + ' not in options.'
1352
1234
  try:
1353
1235
  exchange.create_order('BTC/USDT:USDT', 'limit', 'buy', 1, 20000)
1354
1236
  except Exception as e:
1355
1237
  req_headers = exchange.last_request_headers
1356
1238
  assert req_headers['KC-API-PARTNER'] == id, 'kucoinfutures - id: ' + id + ' not in headers.'
1357
- close(exchange)
1239
+ if not is_sync():
1240
+ close(exchange)
1358
1241
  return True
1359
1242
 
1360
1243
  def test_bitget(self):
1361
1244
  exchange = self.init_offline_exchange('bitget')
1362
1245
  req_headers = None
1363
1246
  id = 'p4sve'
1364
- options_string = str(exchange.options)
1365
- assert exchange.options['broker'] == id, 'bitget - id: ' + id + ' not in options: ' + options_string
1247
+ assert exchange.options['broker'] == id, 'bitget - id: ' + id + ' not in options'
1366
1248
  try:
1367
1249
  exchange.create_order('BTC/USDT', 'limit', 'buy', 1, 20000)
1368
1250
  except Exception as e:
1369
1251
  req_headers = exchange.last_request_headers
1370
1252
  assert req_headers['X-CHANNEL-API-CODE'] == id, 'bitget - id: ' + id + ' not in headers.'
1371
- close(exchange)
1253
+ if not is_sync():
1254
+ close(exchange)
1372
1255
  return True
1373
1256
 
1374
1257
  def test_mexc(self):
1375
1258
  exchange = self.init_offline_exchange('mexc')
1376
1259
  req_headers = None
1377
1260
  id = 'CCXT'
1378
- options_string = str(exchange.options)
1379
- assert exchange.options['broker'] == id, 'mexc - id: ' + id + ' not in options: ' + options_string
1261
+ assert exchange.options['broker'] == id, 'mexc - id: ' + id + ' not in options'
1380
1262
  exchange.load_markets()
1381
1263
  try:
1382
1264
  exchange.create_order('BTC/USDT', 'limit', 'buy', 1, 20000)
1383
1265
  except Exception as e:
1384
1266
  req_headers = exchange.last_request_headers
1385
- req_headers_string = str(req_headers) if req_headers is not None else 'undefined'
1386
- assert req_headers['source'] == id, 'mexc - id: ' + id + ' not in headers: ' + req_headers_string
1387
- close(exchange)
1267
+ assert req_headers['source'] == id, 'mexc - id: ' + id + ' not in headers.'
1268
+ if not is_sync():
1269
+ close(exchange)
1388
1270
  return True
1389
1271
 
1390
1272
  def test_htx(self):
@@ -1414,7 +1296,8 @@ class testMainClass(baseMainTestClass):
1414
1296
  assert client_order_id_swap.startswith(id_string), 'htx - swap channel_code ' + client_order_id_swap + ' does not start with id: ' + id_string
1415
1297
  client_order_id_inverse = swap_inverse_order_request['channel_code']
1416
1298
  assert client_order_id_inverse.startswith(id_string), 'htx - swap inverse channel_code ' + client_order_id_inverse + ' does not start with id: ' + id_string
1417
- close(exchange)
1299
+ if not is_sync():
1300
+ close(exchange)
1418
1301
  return True
1419
1302
 
1420
1303
  def test_woo(self):
@@ -1439,7 +1322,8 @@ class testMainClass(baseMainTestClass):
1439
1322
  stop_order_request = json_parse(exchange.last_request_body)
1440
1323
  client_order_id_stop = stop_order_request['brokerId']
1441
1324
  assert client_order_id_stop.startswith(id_string), 'woo - brokerId: ' + client_order_id_stop + ' does not start with id: ' + id_string
1442
- close(exchange)
1325
+ if not is_sync():
1326
+ close(exchange)
1443
1327
  return True
1444
1328
 
1445
1329
  def test_bitmart(self):
@@ -1453,7 +1337,8 @@ class testMainClass(baseMainTestClass):
1453
1337
  except Exception as e:
1454
1338
  req_headers = exchange.last_request_headers
1455
1339
  assert req_headers['X-BM-BROKER-ID'] == id, 'bitmart - id: ' + id + ' not in headers'
1456
- close(exchange)
1340
+ if not is_sync():
1341
+ close(exchange)
1457
1342
  return True
1458
1343
 
1459
1344
  def test_coinex(self):
@@ -1468,23 +1353,23 @@ class testMainClass(baseMainTestClass):
1468
1353
  client_order_id = spot_order_request['client_id']
1469
1354
  id_string = str(id)
1470
1355
  assert client_order_id.startswith(id_string), 'coinex - clientOrderId: ' + client_order_id + ' does not start with id: ' + id_string
1471
- close(exchange)
1356
+ if not is_sync():
1357
+ close(exchange)
1472
1358
  return True
1473
1359
 
1474
1360
  def test_bingx(self):
1475
1361
  exchange = self.init_offline_exchange('bingx')
1476
1362
  req_headers = None
1477
1363
  id = 'CCXT'
1478
- options_string = str(exchange.options)
1479
- assert exchange.options['broker'] == id, 'bingx - id: ' + id + ' not in options: ' + options_string
1364
+ assert exchange.options['broker'] == id, 'bingx - id: ' + id + ' not in options'
1480
1365
  try:
1481
1366
  exchange.create_order('BTC/USDT', 'limit', 'buy', 1, 20000)
1482
1367
  except Exception as e:
1483
1368
  # we expect an error here, we're only interested in the headers
1484
1369
  req_headers = exchange.last_request_headers
1485
- req_headers_string = str(req_headers) if req_headers is not None else 'undefined'
1486
- assert req_headers['X-SOURCE-KEY'] == id, 'bingx - id: ' + id + ' not in headers: ' + req_headers_string
1487
- close(exchange)
1370
+ assert req_headers['X-SOURCE-KEY'] == id, 'bingx - id: ' + id + ' not in headers.'
1371
+ if not is_sync():
1372
+ close(exchange)
1488
1373
 
1489
1374
  def test_phemex(self):
1490
1375
  exchange = self.init_offline_exchange('phemex')
@@ -1497,7 +1382,8 @@ class testMainClass(baseMainTestClass):
1497
1382
  client_order_id = request['clOrdID']
1498
1383
  id_string = str(id)
1499
1384
  assert client_order_id.startswith(id_string), 'phemex - clOrdID: ' + client_order_id + ' does not start with id: ' + id_string
1500
- close(exchange)
1385
+ if not is_sync():
1386
+ close(exchange)
1501
1387
 
1502
1388
  def test_blofin(self):
1503
1389
  exchange = self.init_offline_exchange('blofin')
@@ -1510,7 +1396,8 @@ class testMainClass(baseMainTestClass):
1510
1396
  broker_id = request['brokerId']
1511
1397
  id_string = str(id)
1512
1398
  assert broker_id.startswith(id_string), 'blofin - brokerId: ' + broker_id + ' does not start with id: ' + id_string
1513
- close(exchange)
1399
+ if not is_sync():
1400
+ close(exchange)
1514
1401
 
1515
1402
  def test_hyperliquid(self):
1516
1403
  exchange = self.init_offline_exchange('hyperliquid')
@@ -1522,7 +1409,8 @@ class testMainClass(baseMainTestClass):
1522
1409
  request = json_parse(exchange.last_request_body)
1523
1410
  broker_id = str((request['action']['brokerCode']))
1524
1411
  assert broker_id == id, 'hyperliquid - brokerId: ' + broker_id + ' does not start with id: ' + id
1525
- close(exchange)
1412
+ if not is_sync():
1413
+ close(exchange)
1526
1414
 
1527
1415
  def test_coinbaseinternational(self):
1528
1416
  exchange = self.init_offline_exchange('coinbaseinternational')
@@ -1536,13 +1424,181 @@ class testMainClass(baseMainTestClass):
1536
1424
  request = json_parse(exchange.last_request_body)
1537
1425
  client_order_id = request['client_order_id']
1538
1426
  assert client_order_id.startswith(str(id)), 'clientOrderId does not start with id'
1539
- close(exchange)
1427
+ if not is_sync():
1428
+ close(exchange)
1540
1429
  return True
1541
1430
 
1542
- # ***** AUTO-TRANSPILER-END *****
1543
- # *******************************
1431
+ def test_coinbase_advanced(self):
1432
+ exchange = self.init_offline_exchange('coinbase')
1433
+ id = 'ccxt'
1434
+ assert exchange.options['brokerId'] == id, 'id not in options'
1435
+ request = None
1436
+ try:
1437
+ exchange.create_order('BTC/USDC', 'limit', 'buy', 1, 20000)
1438
+ except Exception as e:
1439
+ request = json_parse(exchange.last_request_body)
1440
+ client_order_id = request['client_order_id']
1441
+ assert client_order_id.startswith(str(id)), 'clientOrderId does not start with id'
1442
+ if not is_sync():
1443
+ close(exchange)
1444
+ return True
1544
1445
 
1446
+ def test_woofi_pro(self):
1447
+ exchange = self.init_offline_exchange('woofipro')
1448
+ exchange.secret = 'secretsecretsecretsecretsecretsecretsecrets'
1449
+ id = 'CCXT'
1450
+ exchange.load_markets()
1451
+ request = None
1452
+ try:
1453
+ exchange.create_order('BTC/USDC:USDC', 'limit', 'buy', 1, 20000)
1454
+ except Exception as e:
1455
+ request = json_parse(exchange.last_request_body)
1456
+ broker_id = request['order_tag']
1457
+ assert broker_id == id, 'woofipro - id: ' + id + ' different from broker_id: ' + broker_id
1458
+ if not is_sync():
1459
+ close(exchange)
1460
+ return True
1545
1461
 
1546
- if __name__ == '__main__':
1547
- symbol = argv.symbol if argv.symbol else None
1548
- (testMainClass().init(argv.exchange, symbol))
1462
+ def test_oxfun(self):
1463
+ exchange = self.init_offline_exchange('oxfun')
1464
+ exchange.secret = 'secretsecretsecretsecretsecretsecretsecrets'
1465
+ id = 1000
1466
+ exchange.load_markets()
1467
+ request = None
1468
+ try:
1469
+ exchange.create_order('BTC/USD:OX', 'limit', 'buy', 1, 20000)
1470
+ except Exception as e:
1471
+ request = json_parse(exchange.last_request_body)
1472
+ orders = request['orders']
1473
+ first = orders[0]
1474
+ broker_id = first['source']
1475
+ assert broker_id == id, 'oxfun - id: ' + str(id) + ' different from broker_id: ' + str(broker_id)
1476
+ return True
1477
+
1478
+ def test_xt(self):
1479
+ exchange = self.init_offline_exchange('xt')
1480
+ id = 'CCXT'
1481
+ spot_order_request = None
1482
+ try:
1483
+ exchange.create_order('BTC/USDT', 'limit', 'buy', 1, 20000)
1484
+ except Exception as e:
1485
+ spot_order_request = json_parse(exchange.last_request_body)
1486
+ spot_media = spot_order_request['media']
1487
+ assert spot_media == id, 'xt - id: ' + id + ' different from swap tag: ' + spot_media
1488
+ swap_order_request = None
1489
+ try:
1490
+ exchange.create_order('BTC/USDT:USDT', 'limit', 'buy', 1, 20000)
1491
+ except Exception as e:
1492
+ swap_order_request = json_parse(exchange.last_request_body)
1493
+ swap_media = swap_order_request['clientMedia']
1494
+ assert swap_media == id, 'xt - id: ' + id + ' different from swap tag: ' + swap_media
1495
+ if not is_sync():
1496
+ close(exchange)
1497
+ return True
1498
+
1499
+ def test_vertex(self):
1500
+ exchange = self.init_offline_exchange('vertex')
1501
+ exchange.walletAddress = '0xc751489d24a33172541ea451bc253d7a9e98c781'
1502
+ exchange.privateKey = 'c33b1eb4b53108bf52e10f636d8c1236c04c33a712357ba3543ab45f48a5cb0b'
1503
+ exchange.options['v1contracts'] = {
1504
+ 'chain_id': '42161',
1505
+ 'endpoint_addr': '0xbbee07b3e8121227afcfe1e2b82772246226128e',
1506
+ 'book_addrs': ['0x0000000000000000000000000000000000000000', '0x70e5911371472e406f1291c621d1c8f207764d73', '0xf03f457a30e598d5020164a339727ef40f2b8fbc', '0x1c6281a78aa0ed88949c319cba5f0f0de2ce8353', '0xfe653438a1a4a7f56e727509c341d60a7b54fa91', '0xb6304e9a6ca241376a5fc9294daa8fca65ddcdcd', '0x01ec802ae0ab1b2cc4f028b9fe6eb954aef06ed1', '0x0000000000000000000000000000000000000000', '0x9c52d5c4df5a68955ad088a781b4ab364a861e9e', '0x0000000000000000000000000000000000000000', '0x2a3bcda1bb3ef649f3571c96c597c3d2b25edc79', '0x0000000000000000000000000000000000000000', '0x0492ff9807f82856781488015ef7aa5526c0edd6', '0x0000000000000000000000000000000000000000', '0xea884c82418ebc21cd080b8f40ecc4d06a6a6883', '0x0000000000000000000000000000000000000000', '0x5ecf68f983253a818ca8c17a56a4f2fb48d6ec6b', '0x0000000000000000000000000000000000000000', '0xba3f57a977f099905531f7c2f294aad7b56ed254', '0x0000000000000000000000000000000000000000', '0x0ac8c26d207d0c6aabb3644fea18f530c4d6fc8e', '0x0000000000000000000000000000000000000000', '0x8bd80ad7630b3864bed66cf28f548143ea43dc3b', '0x0000000000000000000000000000000000000000', '0x045391227fc4b2cdd27b95f066864225afc9314e', '0x0000000000000000000000000000000000000000', '0x7d512bef2e6cfd7e7f5f6b2f8027e3728eb7b6c3', '0x0000000000000000000000000000000000000000', '0x678a6c5003b56b5e9a81559e9a0df880407c796f', '0x0000000000000000000000000000000000000000', '0x14b5a17208fa98843cc602b3f74e31c95ded3567', '0xe442a89a07b3888ab10579fbb2824aeceff3a282', '0x0000000000000000000000000000000000000000', '0x0000000000000000000000000000000000000000', '0xac28ac205275d7c2d6877bea8657cebe04fd9ae9', '0x0000000000000000000000000000000000000000', '0xed811409bfea901e75cb19ba347c08a154e860c9', '0x0000000000000000000000000000000000000000', '0x0f7afcb1612b305626cff84f84e4169ba2d0f12c', '0x0000000000000000000000000000000000000000', '0xe4b8d903db2ce2d3891ef04cfc3ac56330c1b0c3', '0x5f44362bad629846b7455ad9d36bbc3759a3ef62', '0x0000000000000000000000000000000000000000', '0x0000000000000000000000000000000000000000', '0xa64e04ed4b223a71e524dc7ebb7f28e422ccfdde', '0x0000000000000000000000000000000000000000', '0x2ee573caab73c1d8cf0ca6bd3589b67de79628a4', '0x0000000000000000000000000000000000000000', '0x01bb96883a8a478d4410387d4aaf11067edc2c74', '0x0000000000000000000000000000000000000000', '0xe7ed0c559d905436a867cddf07e06921d572363c', '0x0000000000000000000000000000000000000000', '0xa94f9e3433c92a5cd1925494811a67b1943557d9', '0x0000000000000000000000000000000000000000', '0xa63de7f89ba1270b85f3dcc193ff1a1390a7c7c7', '0x0000000000000000000000000000000000000000', '0xc8b0b37dffe3a711a076dc86dd617cc203f36121', '0x0000000000000000000000000000000000000000', '0x646df48947ff785fe609969ff634e7be9d1c34cd', '0x0000000000000000000000000000000000000000', '0x42582b404b0bec4a266631a0e178840b107a0c69', '0x0000000000000000000000000000000000000000', '0x36a94bc3edb1b629d1413091e22dc65fa050f17f', '0x0000000000000000000000000000000000000000', '0xb398d00b5a336f0ad33cfb352fd7646171cec442', '0x0000000000000000000000000000000000000000', '0xb4bc3b00de98e1c0498699379f6607b1f00bd5a1', '0x0000000000000000000000000000000000000000', '0xfe8b7baf68952bac2c04f386223d2013c1b4c601', '0x0000000000000000000000000000000000000000', '0x9c8764ec71f175c97c6c2fd558eb6546fcdbea32', '0x0000000000000000000000000000000000000000', '0x94d31188982c8eccf243e555b22dc57de1dba4e1', '0x0000000000000000000000000000000000000000', '0x407c5e2fadd7555be927c028bc358daa907c797a', '0x0000000000000000000000000000000000000000', '0x7e97da2dbbbdd7fb313cf9dc0581ac7cec999c70', '0x0000000000000000000000000000000000000000', '0x7f8d2662f64dd468c423805f98a6579ad59b28fa', '0x0000000000000000000000000000000000000000', '0x3398adf63fed17cbadd6080a1fb771e6a2a55958', '0x0000000000000000000000000000000000000000', '0xba8910a1d7ab62129729047d453091a1e6356170', '0x0000000000000000000000000000000000000000', '0xdc054bce222fe725da0f17abcef38253bd8bb745', '0x0000000000000000000000000000000000000000', '0xca21693467d0a5ea9e10a5a7c5044b9b3837e694', '0x0000000000000000000000000000000000000000', '0xe0b02de2139256dbae55cf350094b882fbe629ea', '0x0000000000000000000000000000000000000000', '0x02c38368a6f53858aab5a3a8d91d73eb59edf9b9', '0x0000000000000000000000000000000000000000', '0x0000000000000000000000000000000000000000', '0x0000000000000000000000000000000000000000', '0x0000000000000000000000000000000000000000', '0x0000000000000000000000000000000000000000', '0xfe8c4778843c3cb047ffe7c0c0154a724c05cab9', '0x0000000000000000000000000000000000000000', '0xe2e88862d9b7379e21c82fc4aec8d71bddbcdb4b', '0x0000000000000000000000000000000000000000', '0xbbaff9e73b30f9cea5c01481f12de75050947fd6', '0x0000000000000000000000000000000000000000', '0xa20f6f381fe0fec5a1035d37ebf8890726377ab9', '0x0000000000000000000000000000000000000000', '0xbad68032d012bf35d3a2a177b242e86684027ed0', '0x0000000000000000000000000000000000000000', '0x0e61ca37f0c67e8a8794e45e264970a2a23a513c', '0x0000000000000000000000000000000000000000', '0xa77b7048e378c5270b15918449ededf87c3a3db3', '0x0000000000000000000000000000000000000000', '0x15afca1e6f02b556fa6551021b3493a1e4a7f44f'],
1507
+ }
1508
+ id = 5930043274845996
1509
+ exchange.load_markets()
1510
+ request = None
1511
+ try:
1512
+ exchange.create_order('BTC/USDC:USDC', 'limit', 'buy', 1, 20000)
1513
+ except Exception as e:
1514
+ request = json_parse(exchange.last_request_body)
1515
+ order = request['place_order']
1516
+ broker_id = order['id']
1517
+ assert broker_id == id, 'vertex - id: ' + str(id) + ' different from broker_id: ' + str(broker_id)
1518
+ if not is_sync():
1519
+ close(exchange)
1520
+ return True
1521
+
1522
+ def test_paradex(self):
1523
+ exchange = self.init_offline_exchange('paradex')
1524
+ exchange.walletAddress = '0xc751489d24a33172541ea451bc253d7a9e98c781'
1525
+ exchange.privateKey = 'c33b1eb4b53108bf52e10f636d8c1236c04c33a712357ba3543ab45f48a5cb0b'
1526
+ exchange.options['authToken'] = 'token'
1527
+ exchange.options['systemConfig'] = {
1528
+ 'starknet_gateway_url': 'https://potc-testnet-sepolia.starknet.io',
1529
+ 'starknet_fullnode_rpc_url': 'https://pathfinder.api.testnet.paradex.trade/rpc/v0_7',
1530
+ 'starknet_chain_id': 'PRIVATE_SN_POTC_SEPOLIA',
1531
+ 'block_explorer_url': 'https://voyager.testnet.paradex.trade/',
1532
+ 'paraclear_address': '0x286003f7c7bfc3f94e8f0af48b48302e7aee2fb13c23b141479ba00832ef2c6',
1533
+ 'paraclear_decimals': 8,
1534
+ 'paraclear_account_proxy_hash': '0x3530cc4759d78042f1b543bf797f5f3d647cde0388c33734cf91b7f7b9314a9',
1535
+ 'paraclear_account_hash': '0x41cb0280ebadaa75f996d8d92c6f265f6d040bb3ba442e5f86a554f1765244e',
1536
+ 'oracle_address': '0x2c6a867917ef858d6b193a0ff9e62b46d0dc760366920d631715d58baeaca1f',
1537
+ 'bridged_tokens': [{
1538
+ 'name': 'TEST USDC',
1539
+ 'symbol': 'USDC',
1540
+ 'decimals': 6,
1541
+ 'l1_token_address': '0x29A873159D5e14AcBd63913D4A7E2df04570c666',
1542
+ 'l1_bridge_address': '0x8586e05adc0C35aa11609023d4Ae6075Cb813b4C',
1543
+ 'l2_token_address': '0x6f373b346561036d98ea10fb3e60d2f459c872b1933b50b21fe6ef4fda3b75e',
1544
+ 'l2_bridge_address': '0x46e9237f5408b5f899e72125dd69bd55485a287aaf24663d3ebe00d237fc7ef',
1545
+ }],
1546
+ 'l1_core_contract_address': '0x582CC5d9b509391232cd544cDF9da036e55833Af',
1547
+ 'l1_operator_address': '0x11bACdFbBcd3Febe5e8CEAa75E0Ef6444d9B45FB',
1548
+ 'l1_chain_id': '11155111',
1549
+ 'liquidation_fee': '0.2',
1550
+ }
1551
+ req_headers = None
1552
+ id = 'CCXT'
1553
+ assert exchange.options['broker'] == id, 'paradex - id: ' + id + ' not in options'
1554
+ exchange.load_markets()
1555
+ try:
1556
+ exchange.create_order('BTC/USD:USDC', 'limit', 'buy', 1, 20000)
1557
+ except Exception as e:
1558
+ req_headers = exchange.last_request_headers
1559
+ assert req_headers['PARADEX-PARTNER'] == id, 'paradex - id: ' + id + ' not in headers'
1560
+ if not is_sync():
1561
+ close(exchange)
1562
+ return True
1563
+
1564
+ def test_hashkey(self):
1565
+ exchange = self.init_offline_exchange('hashkey')
1566
+ req_headers = None
1567
+ id = '10000700011'
1568
+ try:
1569
+ exchange.create_order('BTC/USDT', 'limit', 'buy', 1, 20000)
1570
+ except Exception as e:
1571
+ # we expect an error here, we're only interested in the headers
1572
+ req_headers = exchange.last_request_headers
1573
+ assert req_headers['INPUT-SOURCE'] == id, 'hashkey - id: ' + id + ' not in headers.'
1574
+ if not is_sync():
1575
+ close(exchange)
1576
+ return True
1577
+
1578
+ def test_coincatch(self):
1579
+ exchange = self.init_offline_exchange('coincatch')
1580
+ req_headers = None
1581
+ id = '47cfy'
1582
+ try:
1583
+ exchange.create_order('BTC/USDT', 'limit', 'buy', 1, 20000)
1584
+ except Exception as e:
1585
+ # we expect an error here, we're only interested in the headers
1586
+ req_headers = exchange.last_request_headers
1587
+ assert req_headers['X-CHANNEL-API-CODE'] == id, 'coincatch - id: ' + id + ' not in headers.'
1588
+ if not is_sync():
1589
+ close(exchange)
1590
+ return True
1591
+
1592
+ def test_defx(self):
1593
+ exchange = self.init_offline_exchange('defx')
1594
+ req_headers = None
1595
+ try:
1596
+ exchange.create_order('DOGE/USDC:USDC', 'limit', 'buy', 100, 1)
1597
+ except Exception as e:
1598
+ # we expect an error here, we're only interested in the headers
1599
+ req_headers = exchange.last_request_headers
1600
+ id = 'ccxt'
1601
+ assert req_headers['X-DEFX-SOURCE'] == id, 'defx - id: ' + id + ' not in headers.'
1602
+ if not is_sync():
1603
+ close(exchange)
1604
+ return True