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,273 +1,39 @@
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.async_support as ccxt # noqa: E402
21
- import ccxt.pro as ccxtpro # noqa: E402
22
-
23
- # ------------------------------------------------------------------------------
24
3
  import asyncio
25
- # from typing import Optional
26
- # from typing import List
27
- from ccxt.base.errors import NotSupported
28
- from ccxt.base.errors import ProxyError
29
- from ccxt.base.errors import OperationFailed
30
- # from ccxt.base.errors import ExchangeError
31
- from ccxt.base.errors import ExchangeNotAvailable
32
- from ccxt.base.errors import OnMaintenance
33
- from ccxt.base.errors import AuthenticationError
34
-
35
- # ------------------------------------------------------------------------------
36
-
37
- class Argv(object):
38
- id_tests = False
39
- static_tests = False
40
- ws_tests = False
41
- request_tests = False
42
- response_tests = False
43
- token_bucket = False
44
- sandbox = False
45
- privateOnly = False
46
- private = False
47
- ws = False
48
- verbose = False
49
- nonce = None
50
- exchange = None
51
- symbol = None
52
- info = False
53
- pass
54
-
55
-
56
- argv = Argv()
57
- parser = argparse.ArgumentParser()
58
- parser.add_argument('--token_bucket', action='store_true', help='enable token bucket experimental test')
59
- parser.add_argument('--sandbox', action='store_true', help='enable sandbox mode')
60
- parser.add_argument('--privateOnly', action='store_true', help='run private tests only')
61
- parser.add_argument('--private', action='store_true', help='run private tests')
62
- parser.add_argument('--verbose', action='store_true', help='enable verbose output')
63
- parser.add_argument('--ws', action='store_true', help='websockets version')
64
- parser.add_argument('--info', action='store_true', help='enable info output')
65
- parser.add_argument('--static', action='store_true', help='run static tests')
66
- parser.add_argument('--useProxy', action='store_true', help='run static tests')
67
- parser.add_argument('--idTests', action='store_true', help='run brokerId tests')
68
- parser.add_argument('--responseTests', action='store_true', help='run response tests')
69
- parser.add_argument('--requestTests', action='store_true', help='run response tests')
70
- parser.add_argument('--nonce', type=int, help='integer')
71
- parser.add_argument('exchange', type=str, help='exchange id in lowercase', nargs='?')
72
- parser.add_argument('symbol', type=str, help='symbol in uppercase', nargs='?')
73
- parser.parse_args(namespace=argv)
74
-
75
- # ------------------------------------------------------------------------------
76
-
77
- path = os.path.dirname(ccxt.__file__)
78
- if 'site-packages' in os.path.dirname(ccxt.__file__):
79
- 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")
80
-
81
- # ------------------------------------------------------------------------------
82
-
83
- Error = Exception
84
4
 
85
- # # print an error string
86
- # def dump_error(*args):
87
- # string = ' '.join([str(arg) for arg in args])
88
- # print(string)
89
- # sys.stderr.write(string + "\n")
90
- # sys.stderr.flush()
91
5
 
6
+ 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
92
7
 
93
- def handle_all_unhandled_exceptions(type, value, traceback):
94
- dump((type), (value), '\n<UNHANDLED EXCEPTION>\n' + ('\n'.join(format_tb(traceback))))
95
- exit(1) # unrecoverable crash
96
-
97
-
98
- sys.excepthook = handle_all_unhandled_exceptions
99
- # ------------------------------------------------------------------------------
100
-
101
- # non-transpiled part, but shared names among langs
102
-
103
- is_synchronous = 'async' not in os.path.basename(__file__)
104
-
105
- rootDir = DIR_NAME + '/../../../'
106
- rootDirForSkips = DIR_NAME + '/../../../'
107
- envVars = os.environ
108
- LOG_CHARS_LENGTH = 10000
109
- ext = 'py'
110
- proxyTestFileName = 'proxies'
111
-
112
-
113
- def get_cli_arg_value(arg):
114
- arg_exists = getattr(argv, arg) if hasattr(argv, arg) else False
115
- with_hyphen = '--' + arg
116
- arg_exists_with_hyphen = getattr(argv, with_hyphen) if hasattr(argv, with_hyphen) else False
117
- without_hyphen = arg.replace('--', '')
118
- arg_exists_wo_hyphen = getattr(argv, without_hyphen) if hasattr(argv, without_hyphen) else False
119
- return arg_exists or arg_exists_with_hyphen or arg_exists_wo_hyphen
120
-
121
- isWsTests = get_cli_arg_value('--ws')
122
-
123
-
124
- class baseMainTestClass():
125
- lang = 'PY'
126
- is_synchronous = is_synchronous
8
+ class testMainClass:
9
+ id_tests = False
127
10
  request_tests_failed = False
128
11
  response_tests_failed = False
129
- response_tests = False
12
+ request_tests = False
130
13
  ws_tests = False
14
+ response_tests = False
15
+ static_tests = False
16
+ info = False
17
+ verbose = False
18
+ debug = False
19
+ private_test = False
20
+ private_test_only = False
131
21
  load_keys = False
22
+ sandbox = False
23
+ only_specific_tests = []
24
+ skipped_settings_for_exchange = {}
132
25
  skipped_methods = {}
133
- check_public_tests = {}
26
+ checked_public_tests = {}
134
27
  test_files = {}
135
28
  public_tests = {}
136
- new_line = '\n'
137
- root_dir = rootDir
138
- env_vars = envVars
139
- ext = ext
140
- root_dir_for_skips = rootDirForSkips
141
- only_specific_tests = []
142
- proxy_test_file_name = proxyTestFileName
143
- pass
144
-
145
-
146
- def dump(*args):
147
- print(' '.join([str(arg) for arg in args]))
148
-
149
-
150
- def convert_ascii(str):
151
- return str # stub
152
-
153
- def json_parse(elem):
154
- return json.loads(elem)
155
-
156
-
157
- def json_stringify(elem):
158
- return json.dumps(elem)
159
-
160
-
161
- def convert_to_snake_case(content):
162
- res = re.sub(r'(?<!^)(?=[A-Z])', '_', content).lower()
163
- return res.replace('o_h_l_c_v', 'ohlcv')
164
-
165
-
166
- def get_test_name(methodName):
167
- # stub
168
- return methodName
169
-
170
-
171
- def io_file_exists(path):
172
- return os.path.isfile(path)
173
-
174
-
175
- def io_file_read(path, decode=True):
176
- fs = open(path, "r", encoding="utf-8")
177
- content = fs.read()
178
- if decode:
179
- return json.loads(content)
180
- else:
181
- return content
182
-
183
-
184
- def io_dir_read(path):
185
- return os.listdir(path)
186
-
187
-
188
- async def call_method(test_files, methodName, exchange, skippedProperties, args):
189
- methodNameToCall = 'test_' + convert_to_snake_case(methodName)
190
- return await getattr(test_files[methodName], methodNameToCall)(exchange, skippedProperties, *args)
29
+ ext = ''
30
+ lang = ''
31
+ proxy_test_file_name = 'proxies'
191
32
 
192
-
193
- async def call_exchange_method_dynamically(exchange, methodName, args):
194
- return await getattr(exchange, methodName)(*args)
195
-
196
- async def call_overriden_method(exchange, methodName, args):
197
- # needed for php
198
- return await call_exchange_method_dynamically(exchange, methodName, args)
199
-
200
- def exception_message(exc):
201
- message = '[' + type(exc).__name__ + '] ' + "".join(format_exception(type(exc), exc, exc.__traceback__, limit=6))
202
- if len(message) > LOG_CHARS_LENGTH:
203
- # Accessing out of range element causes error
204
- message = message[0:LOG_CHARS_LENGTH]
205
- return message
206
-
207
-
208
- def exit_script(code=0):
209
- exit(code)
210
-
211
-
212
- def get_exchange_prop(exchange, prop, defaultValue=None):
213
- if hasattr(exchange, prop):
214
- res = getattr(exchange, prop)
215
- if res is not None and res != '':
216
- return res
217
- return defaultValue
218
-
219
-
220
- def set_exchange_prop(exchange, prop, value):
221
- setattr(exchange, prop, value)
222
- # set snake case too
223
- setattr(exchange, convert_to_snake_case(prop), value)
224
-
225
-
226
- def init_exchange(exchangeId, args, is_ws=False):
227
- if (is_ws):
228
- return getattr(ccxtpro, exchangeId)(args)
229
- return getattr(ccxt, exchangeId)(args)
230
-
231
-
232
- async def get_test_files(properties, ws=False):
233
- tests = {}
234
- finalPropList = properties + [proxyTestFileName]
235
- for i in range(0, len(finalPropList)):
236
- methodName = finalPropList[i]
237
- name_snake_case = convert_to_snake_case(methodName)
238
- prefix = 'async' if not is_synchronous else 'sync'
239
- dir_to_test = DIR_NAME + '/' + prefix + '/'
240
- module_string = 'ccxt.test.' + prefix + '.test_' + name_snake_case
241
- if (ws):
242
- prefix = 'pro'
243
- dir_to_test = DIR_NAME + '/../' + prefix + '/test/Exchange/'
244
- module_string = 'ccxt.pro.test.Exchange.test_' + name_snake_case
245
- filePathWithExt = dir_to_test + 'test_' + name_snake_case + '.py'
246
- if (io_file_exists (filePathWithExt)):
247
- imp = importlib.import_module(module_string)
248
- tests[methodName] = imp # getattr(imp, finalName)
249
- return tests
250
-
251
- async def close(exchange):
252
- if (not is_synchronous and hasattr(exchange, 'close')):
253
- await exchange.close()
254
-
255
- def is_null_value(value):
256
- return value is None
257
-
258
- def set_fetch_response(exchange: ccxt.Exchange, data):
259
- async def fetch(url, method='GET', headers=None, body=None):
260
- return data
261
- exchange.fetch = fetch
262
- return exchange
263
-
264
- # *********************************
265
- # ***** AUTO-TRANSPILER-START *****
266
- class testMainClass(baseMainTestClass):
267
- def parse_cli_args(self):
268
- self.response_tests = get_cli_arg_value('--responseTests')
33
+ def parse_cli_args_and_props(self):
34
+ self.response_tests = get_cli_arg_value('--responseTests') or get_cli_arg_value('--response')
269
35
  self.id_tests = get_cli_arg_value('--idTests')
270
- self.request_tests = get_cli_arg_value('--requestTests')
36
+ self.request_tests = get_cli_arg_value('--requestTests') or get_cli_arg_value('--request')
271
37
  self.info = get_cli_arg_value('--info')
272
38
  self.verbose = get_cli_arg_value('--verbose')
273
39
  self.debug = get_cli_arg_value('--debug')
@@ -276,9 +42,11 @@ class testMainClass(baseMainTestClass):
276
42
  self.sandbox = get_cli_arg_value('--sandbox')
277
43
  self.load_keys = get_cli_arg_value('--loadKeys')
278
44
  self.ws_tests = get_cli_arg_value('--ws')
45
+ self.lang = get_lang()
46
+ self.ext = get_ext()
279
47
 
280
- async def init(self, exchange_id, symbol_argv):
281
- self.parse_cli_args()
48
+ async def init(self, exchange_id, symbol_argv, method_argv):
49
+ self.parse_cli_args_and_props()
282
50
  if self.request_tests and self.response_tests:
283
51
  await self.run_static_request_tests(exchange_id, symbol_argv)
284
52
  await self.run_static_response_tests(exchange_id, symbol_argv)
@@ -292,13 +60,14 @@ class testMainClass(baseMainTestClass):
292
60
  if self.id_tests:
293
61
  await self.run_broker_id_tests()
294
62
  return
295
- symbol_str = symbol_argv if symbol_argv is not None else 'all'
296
- exchange_object = {
63
+ new_line = '\n'
64
+ dump(new_line + '' + new_line + '' + '[INFO] TESTING ', self.ext, {
297
65
  'exchange': exchange_id,
298
- 'symbol': symbol_str,
66
+ 'symbol': symbol_argv,
67
+ 'method': method_argv,
299
68
  'isWs': self.ws_tests,
300
- }
301
- dump(self.new_line + '' + self.new_line + '' + '[INFO] TESTING ', self.ext, json_stringify(exchange_object), self.new_line)
69
+ 'useProxy': get_cli_arg_value('--useProxy'),
70
+ }, new_line)
302
71
  exchange_args = {
303
72
  'verbose': self.verbose,
304
73
  'debug': self.debug,
@@ -311,30 +80,30 @@ class testMainClass(baseMainTestClass):
311
80
  await self.import_files(exchange)
312
81
  assert len(list(self.test_files.keys())) > 0, 'Test files were not loaded' # ensure test files are found & filled
313
82
  self.expand_settings(exchange)
314
- symbol = self.check_if_specific_test_is_chosen(symbol_argv)
315
- await self.start_test(exchange, symbol)
83
+ self.check_if_specific_test_is_chosen(method_argv)
84
+ await self.start_test(exchange, symbol_argv)
316
85
  exit_script(0) # needed to be explicitly finished for WS tests
317
86
 
318
- def check_if_specific_test_is_chosen(self, symbol_argv):
319
- if symbol_argv is not None:
87
+ def check_if_specific_test_is_chosen(self, method_argv):
88
+ if method_argv is not None:
320
89
  test_file_names = list(self.test_files.keys())
321
- possible_method_names = symbol_argv.split(',') # i.e. `test.ts binance fetchBalance,fetchDeposits`
90
+ possible_method_names = method_argv.split(',') # i.e. `test.ts binance fetchBalance,fetchDeposits`
322
91
  if len(possible_method_names) >= 1:
323
92
  for i in range(0, len(test_file_names)):
324
93
  test_file_name = test_file_names[i]
325
94
  for j in range(0, len(possible_method_names)):
326
95
  method_name = possible_method_names[j]
96
+ method_name = method_name.replace('()', '')
327
97
  if test_file_name == method_name:
328
98
  self.only_specific_tests.append(test_file_name)
329
- # if method names were found, then remove them from symbolArgv
330
- if len(self.only_specific_tests) > 0:
331
- return None
332
- return symbol_argv
333
99
 
334
100
  async def import_files(self, exchange):
335
101
  properties = list(exchange.has.keys())
336
102
  properties.append('loadMarkets')
337
- self.test_files = await get_test_files(properties, self.ws_tests)
103
+ if is_sync():
104
+ self.test_files = get_test_files_sync(properties, self.ws_tests)
105
+ else:
106
+ self.test_files = await get_test_files(properties, self.ws_tests)
338
107
 
339
108
  def load_credentials_from_env(self, exchange):
340
109
  exchange_id = exchange.id
@@ -346,14 +115,15 @@ class testMainClass(baseMainTestClass):
346
115
  if is_required and get_exchange_prop(exchange, credential) is None:
347
116
  full_key = exchange_id + '_' + credential
348
117
  credential_env_name = full_key.upper() # example: KRAKEN_APIKEY
349
- credential_value = self.env_vars[credential_env_name] if (credential_env_name in self.env_vars) else None
118
+ env_vars = get_env_vars()
119
+ credential_value = env_vars[credential_env_name] if (credential_env_name in env_vars) else None
350
120
  if credential_value:
351
121
  set_exchange_prop(exchange, credential, credential_value)
352
122
 
353
123
  def expand_settings(self, exchange):
354
124
  exchange_id = exchange.id
355
- keys_global = self.root_dir + 'keys.json'
356
- keys_local = self.root_dir + 'keys.local.json'
125
+ keys_global = get_root_dir() + 'keys.json'
126
+ keys_local = get_root_dir() + 'keys.local.json'
357
127
  keys_global_exists = io_file_exists(keys_global)
358
128
  keys_local_exists = io_file_exists(keys_local)
359
129
  global_settings = io_file_read(keys_global) if keys_global_exists else {}
@@ -376,9 +146,10 @@ class testMainClass(baseMainTestClass):
376
146
  if self.load_keys:
377
147
  self.load_credentials_from_env(exchange)
378
148
  # skipped tests
379
- skipped_file = self.root_dir_for_skips + 'skip-tests.json'
149
+ skipped_file = get_root_dir() + 'skip-tests.json'
380
150
  skipped_settings = io_file_read(skipped_file)
381
- skipped_settings_for_exchange = exchange.safe_value(skipped_settings, exchange_id, {})
151
+ self.skipped_settings_for_exchange = exchange.safe_value(skipped_settings, exchange_id, {})
152
+ skipped_settings_for_exchange = self.skipped_settings_for_exchange
382
153
  # others
383
154
  timeout = exchange.safe_value(skipped_settings_for_exchange, 'timeout')
384
155
  if timeout is not None:
@@ -401,31 +172,18 @@ class testMainClass(baseMainTestClass):
401
172
  res += ' '
402
173
  return message + res
403
174
 
404
- def exchange_hint(self, exchange, market=None):
405
- market_type = exchange.safe_string_2(exchange.options, 'defaultType', 'type', '')
406
- market_sub_type = exchange.safe_string_2(exchange.options, 'defaultSubType', 'subType')
407
- if market is not None:
408
- market_type = market['type']
409
- if market['linear']:
410
- market_sub_type = 'linear'
411
- elif market['inverse']:
412
- market_sub_type = 'inverse'
413
- elif exchange.safe_value(market, 'quanto'):
414
- market_sub_type = 'quanto'
415
- is_ws = ('ws' in exchange.has)
416
- ws_flag = '(WS)' if is_ws else ''
417
- result = exchange.id + ' ' + ws_flag + ' ' + market_type
418
- if market_sub_type is not None:
419
- result = result + ' [subType: ' + market_sub_type + '] '
420
- return result
421
-
422
175
  async def test_method(self, method_name, exchange, args, is_public):
176
+ # todo: temporary skip for c#
177
+ if 'OrderBook' in method_name and self.ext == 'cs':
178
+ exchange.options['checksum'] = False
423
179
  # todo: temporary skip for php
424
180
  if 'OrderBook' in method_name and self.ext == 'php':
425
181
  return
182
+ skipped_properties_for_method = self.get_skips(exchange, method_name)
426
183
  is_load_markets = (method_name == 'loadMarkets')
427
184
  is_fetch_currencies = (method_name == 'fetchCurrencies')
428
185
  is_proxy_test = (method_name == self.proxy_test_file_name)
186
+ is_feature_test = (method_name == 'features')
429
187
  # 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)
430
188
  if not is_public and (method_name in self.checked_public_tests) and not is_fetch_currencies:
431
189
  return
@@ -433,31 +191,46 @@ class testMainClass(baseMainTestClass):
433
191
  supported_by_exchange = (method_name in exchange.has) and exchange.has[method_name]
434
192
  if not is_load_markets and (len(self.only_specific_tests) > 0 and not exchange.in_array(method_name, self.only_specific_tests)):
435
193
  skip_message = '[INFO] IGNORED_TEST'
436
- elif not is_load_markets and not supported_by_exchange and not is_proxy_test:
194
+ elif not is_load_markets and not supported_by_exchange and not is_proxy_test and not is_feature_test:
437
195
  skip_message = '[INFO] UNSUPPORTED_TEST' # keep it aligned with the longest message
438
- elif (method_name in self.skipped_methods) and (isinstance(self.skipped_methods[method_name], str)):
196
+ elif isinstance(skipped_properties_for_method, str):
439
197
  skip_message = '[INFO] SKIPPED_TEST'
440
198
  elif not (method_name in self.test_files):
441
199
  skip_message = '[INFO] UNIMPLEMENTED_TEST'
442
200
  # 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)
443
201
  if is_load_markets:
444
202
  await exchange.load_markets(True)
203
+ name = exchange.id
445
204
  if skip_message:
446
205
  if self.info:
447
- dump(self.add_padding(skip_message, 25), self.exchange_hint(exchange), method_name)
206
+ dump(self.add_padding(skip_message, 25), name, method_name)
448
207
  return
449
208
  if self.info:
450
- args_stringified = '(' + ','.join(args) + ')'
451
- dump(self.add_padding('[INFO] TESTING', 25), self.exchange_hint(exchange), method_name, args_stringified)
452
- await call_method(self.test_files, method_name, exchange, self.get_skips(exchange, method_name), args)
453
- # if it was passed successfully, add to the list of successfull tests
209
+ 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"
210
+ dump(self.add_padding('[INFO] TESTING', 25), name, method_name, args_stringified)
211
+ if is_sync():
212
+ call_method_sync(self.test_files, method_name, exchange, skipped_properties_for_method, args)
213
+ else:
214
+ await call_method(self.test_files, method_name, exchange, skipped_properties_for_method, args)
215
+ if self.info:
216
+ dump(self.add_padding('[INFO] TESTING DONE', 25), name, method_name)
217
+ # add to the list of successed tests
454
218
  if is_public:
455
219
  self.checked_public_tests[method_name] = True
456
220
  return
457
221
 
458
222
  def get_skips(self, exchange, method_name):
459
- # get "method-specific" skips
460
- skips_for_method = exchange.safe_value(self.skipped_methods, method_name, {})
223
+ final_skips = {}
224
+ # check the exact method (i.e. `fetchTrades`) and language-specific (i.e. `fetchTrades.php`)
225
+ method_names = [method_name, method_name + '.' + self.ext]
226
+ for i in range(0, len(method_names)):
227
+ m_name = method_names[i]
228
+ if m_name in self.skipped_methods:
229
+ # if whole method is skipped, by assigning a string to it, i.e. "fetchOrders":"blabla"
230
+ if isinstance(self.skipped_methods[m_name], str):
231
+ return self.skipped_methods[m_name]
232
+ else:
233
+ final_skips = exchange.deep_extend(final_skips, self.skipped_methods[m_name])
461
234
  # get "object-specific" skips
462
235
  object_skips = {
463
236
  'orderBook': ['fetchOrderBook', 'fetchOrderBooks', 'fetchL2OrderBook', 'watchOrderBook', 'watchOrderBookForSymbols'],
@@ -473,9 +246,21 @@ class testMainClass(baseMainTestClass):
473
246
  object_name = object_names[i]
474
247
  object_methods = object_skips[object_name]
475
248
  if exchange.in_array(method_name, object_methods):
249
+ # if whole object is skipped, by assigning a string to it, i.e. "orderBook":"blabla"
250
+ if (object_name in self.skipped_methods) and (isinstance(self.skipped_methods[object_name], str)):
251
+ return self.skipped_methods[object_name]
476
252
  extra_skips = exchange.safe_dict(self.skipped_methods, object_name, {})
477
- return exchange.deep_extend(skips_for_method, extra_skips)
478
- return skips_for_method
253
+ final_skips = exchange.deep_extend(final_skips, extra_skips)
254
+ # extend related skips
255
+ # - if 'timestamp' is skipped, we should do so for 'datetime' too
256
+ # - if 'bid' is skipped, skip 'ask' too
257
+ if ('timestamp' in final_skips) and not ('datetime' in final_skips):
258
+ final_skips['datetime'] = final_skips['timestamp']
259
+ if ('bid' in final_skips) and not ('ask' in final_skips):
260
+ final_skips['ask'] = final_skips['bid']
261
+ if ('baseVolume' in final_skips) and not ('quoteVolume' in final_skips):
262
+ final_skips['quoteVolume'] = final_skips['baseVolume']
263
+ return final_skips
479
264
 
480
265
  async def test_safe(self, method_name, exchange, args=[], is_public=False):
481
266
  # `testSafe` method does not throw an exception, instead mutes it. The reason we
@@ -484,12 +269,13 @@ class testMainClass(baseMainTestClass):
484
269
  # formatted message "[TEST_FAILURE] ..." and that output is then regex-matched by
485
270
  # run-tests.js, so the exceptions are still printed out to console from there.
486
271
  max_retries = 3
487
- args_stringified = exchange.json(args) # args.join() breaks when we provide a list of symbols | "args.toString()" breaks bcz of "array to string conversion"
272
+ 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"
488
273
  for i in range(0, max_retries):
489
274
  try:
490
275
  await self.test_method(method_name, exchange, args, is_public)
491
276
  return True
492
- except Exception as e:
277
+ except Exception as ex:
278
+ e = get_root_exception(ex)
493
279
  is_load_markets = (method_name == 'loadMarkets')
494
280
  is_auth_error = (isinstance(e, AuthenticationError))
495
281
  is_not_supported = (isinstance(e, NotSupported))
@@ -521,36 +307,37 @@ class testMainClass(baseMainTestClass):
521
307
  return_success = True
522
308
  # output the message
523
309
  fail_type = '[TEST_FAILURE]' if should_fail else '[TEST_WARNING]'
524
- 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))
310
+ dump(fail_type, 'Method could not be tested due to a repeated Network/Availability issues', ' | ', exchange.id, method_name, args_stringified, exception_message(e))
525
311
  return return_success
526
312
  else:
527
313
  # wait and retry again
528
314
  # (increase wait time on every retry)
529
- await exchange.sleep(i * 1000)
315
+ await exchange.sleep((i + 1) * 1000)
530
316
  continue
531
317
  else:
532
318
  # if it's loadMarkets, then fail test, because it's mandatory for tests
533
319
  if is_load_markets:
534
- dump('[TEST_FAILURE]', 'Exchange can not load markets', exception_message(e), self.exchange_hint(exchange), method_name, args_stringified)
320
+ dump('[TEST_FAILURE]', 'Exchange can not load markets', exception_message(e), exchange.id, method_name, args_stringified)
535
321
  return False
536
322
  # if the specific arguments to the test method throws "NotSupported" exception
537
323
  # then let's don't fail the test
538
324
  if is_not_supported:
539
325
  if self.info:
540
- dump('[INFO] NOT_SUPPORTED', exception_message(e), self.exchange_hint(exchange), method_name, args_stringified)
326
+ dump('[INFO] NOT_SUPPORTED', exception_message(e), exchange.id, method_name, args_stringified)
541
327
  return True
542
328
  # If public test faces authentication error, we don't break (see comments under `testSafe` method)
543
329
  if is_public and is_auth_error:
544
330
  if self.info:
545
- dump('[INFO]', 'Authentication problem for public method', exception_message(e), self.exchange_hint(exchange), method_name, args_stringified)
331
+ dump('[INFO]', 'Authentication problem for public method', exception_message(e), exchange.id, method_name, args_stringified)
546
332
  return True
547
333
  else:
548
- dump('[TEST_FAILURE]', exception_message(e), self.exchange_hint(exchange), method_name, args_stringified)
334
+ dump('[TEST_FAILURE]', exception_message(e), exchange.id, method_name, args_stringified)
549
335
  return False
550
336
  return True
551
337
 
552
338
  async def run_public_tests(self, exchange, symbol):
553
339
  tests = {
340
+ 'features': [],
554
341
  'fetchCurrencies': [],
555
342
  'fetchTicker': [symbol],
556
343
  'fetchTickers': [symbol],
@@ -567,10 +354,14 @@ class testMainClass(baseMainTestClass):
567
354
  if self.ws_tests:
568
355
  tests = {
569
356
  'watchOHLCV': [symbol],
357
+ 'watchOHLCVForSymbols': [symbol],
570
358
  'watchTicker': [symbol],
571
359
  'watchTickers': [symbol],
360
+ 'watchBidsAsks': [symbol],
572
361
  'watchOrderBook': [symbol],
362
+ 'watchOrderBookForSymbols': [[symbol]],
573
363
  'watchTrades': [symbol],
364
+ 'watchTradesForSymbols': [[symbol]],
574
365
  }
575
366
  market = exchange.market(symbol)
576
367
  is_spot = market['spot']
@@ -607,34 +398,26 @@ class testMainClass(baseMainTestClass):
607
398
  test_prefix_string = 'PUBLIC_TESTS' if is_public_test else 'PRIVATE_TESTS'
608
399
  if len(failed_methods):
609
400
  errors_string = ', '.join(failed_methods)
610
- dump('[TEST_FAILURE]', self.exchange_hint(exchange), test_prefix_string, 'Failed methods : ' + errors_string)
401
+ dump('[TEST_FAILURE]', exchange.id, test_prefix_string, 'Failed methods : ' + errors_string)
611
402
  if self.info:
612
- dump(self.add_padding('[INFO] END ' + test_prefix_string + ' ' + self.exchange_hint(exchange), 25))
403
+ dump(self.add_padding('[INFO] END ' + test_prefix_string + ' ' + exchange.id, 25))
613
404
 
614
405
  async def load_exchange(self, exchange):
615
406
  result = await self.test_safe('loadMarkets', exchange, [], True)
616
407
  if not result:
617
408
  return False
618
- 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']
619
- result_symbols = []
620
- exchange_specific_symbols = exchange.symbols
621
- for i in range(0, len(exchange_specific_symbols)):
622
- symbol = exchange_specific_symbols[i]
623
- if exchange.in_array(symbol, symbols):
624
- result_symbols.append(symbol)
625
- result_msg = ''
626
- result_length = len(result_symbols)
627
409
  exchange_symbols_length = len(exchange.symbols)
628
- if result_length > 0:
629
- if exchange_symbols_length > result_length:
630
- result_msg = ', '.join(result_symbols) + ' + more...'
631
- else:
632
- result_msg = ', '.join(result_symbols)
633
- dump('[INFO:MAIN] Exchange loaded', exchange_symbols_length, 'symbols', result_msg)
410
+ dump('[INFO:MAIN] Exchange loaded', exchange_symbols_length, 'symbols')
634
411
  return True
635
412
 
636
413
  def get_test_symbol(self, exchange, is_spot, symbols):
637
414
  symbol = None
415
+ preferred_spot_symbol = exchange.safe_string(self.skipped_settings_for_exchange, 'preferredSpotSymbol')
416
+ preferred_swap_symbol = exchange.safe_string(self.skipped_settings_for_exchange, 'preferredSwapSymbol')
417
+ if is_spot and preferred_spot_symbol:
418
+ return preferred_spot_symbol
419
+ elif not is_spot and preferred_swap_symbol:
420
+ return preferred_swap_symbol
638
421
  for i in range(0, len(symbols)):
639
422
  s = symbols[i]
640
423
  market = exchange.safe_value(exchange.markets, s)
@@ -669,9 +452,9 @@ class testMainClass(baseMainTestClass):
669
452
 
670
453
  def get_valid_symbol(self, exchange, spot=True):
671
454
  current_type_markets = self.get_markets_from_exchange(exchange, spot)
672
- 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']
673
- 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']
674
- 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']
455
+ codes = ['BTC', 'ETH', 'XRP', 'LTC', 'BNB', 'DASH', 'DOGE', 'ETC', 'TRX', 'USDT', 'USDC', 'USD', 'EUR', 'TUSD', 'CNY', 'JPY', 'BRL']
456
+ 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']
457
+ 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']
675
458
  target_symbols = spot_symbols if spot else swap_symbols
676
459
  symbol = self.get_test_symbol(exchange, spot, target_symbols)
677
460
  # if symbols wasn't found from above hardcoded list, then try to locate any symbol which has our target hardcoded 'base' code
@@ -779,6 +562,8 @@ class testMainClass(baseMainTestClass):
779
562
  'fetchBorrowRateHistory': [code],
780
563
  'fetchLedgerEntry': [code],
781
564
  }
565
+ if get_cli_arg_value('--fundedTests'):
566
+ tests['createOrder'] = [symbol]
782
567
  if self.ws_tests:
783
568
  tests = {
784
569
  'watchBalance': [code],
@@ -809,7 +594,7 @@ class testMainClass(baseMainTestClass):
809
594
  # these tests should be synchronously executed, because of conflicting nature of proxy settings
810
595
  proxy_test_name = self.proxy_test_file_name
811
596
  # todo: temporary skip for sync py
812
- if self.ext == 'py' and self.is_synchronous:
597
+ if self.ext == 'py' and is_sync():
813
598
  return
814
599
  # try proxy several times
815
600
  max_retries = 3
@@ -817,12 +602,16 @@ class testMainClass(baseMainTestClass):
817
602
  for j in range(0, max_retries):
818
603
  try:
819
604
  await self.test_method(proxy_test_name, exchange, [], True)
820
- break # if successfull, then break
605
+ return # if successfull, then end the test
821
606
  except Exception as e:
822
607
  exception = e
608
+ await exchange.sleep(j * 1000)
823
609
  # if exception was set, then throw it
824
- if exception:
610
+ if exception is not None:
825
611
  error_message = '[TEST_FAILURE] Failed ' + proxy_test_name + ' : ' + exception_message(exception)
612
+ # temporary comment the below, because c# transpilation failure
613
+ # throw new Exchange Error (errorMessage.toString ());
614
+ dump('[TEST_WARNING]' + str(error_message))
826
615
 
827
616
  async def start_test(self, exchange, symbol):
828
617
  # we do not need to test aliases
@@ -833,16 +622,19 @@ class testMainClass(baseMainTestClass):
833
622
  try:
834
623
  result = await self.load_exchange(exchange)
835
624
  if not result:
836
- await close(exchange)
625
+ if not is_sync():
626
+ await close(exchange)
837
627
  return
838
628
  # if (exchange.id === 'binance') {
839
629
  # # 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
840
630
  # # await this.testProxies (exchange);
841
631
  # }
842
632
  await self.test_exchange(exchange, symbol)
843
- await close(exchange)
633
+ if not is_sync():
634
+ await close(exchange)
844
635
  except Exception as e:
845
- await close(exchange)
636
+ if not is_sync():
637
+ await close(exchange)
846
638
  raise e
847
639
 
848
640
  def assert_static_error(self, cond, message, calculated_output, stored_output, key=None):
@@ -851,9 +643,10 @@ class testMainClass(baseMainTestClass):
851
643
  # -----------------------------------------------------------------------------
852
644
  calculated_string = json_stringify(calculated_output)
853
645
  stored_string = json_stringify(stored_output)
854
- error_message = message + ' computed ' + stored_string + ' stored: ' + calculated_string
646
+ error_message = message
855
647
  if key is not None:
856
- error_message = ' | ' + key + ' | ' + 'computed value: ' + stored_string + ' stored value: ' + calculated_string
648
+ error_message = '[' + key + ']'
649
+ error_message += ' computed: ' + stored_string + ' stored: ' + calculated_string
857
650
  assert cond, error_message
858
651
 
859
652
  def load_markets_from_file(self, id):
@@ -861,12 +654,12 @@ class testMainClass(baseMainTestClass):
861
654
  # to make this test as fast as possible
862
655
  # and basically independent from the exchange
863
656
  # so we can run it offline
864
- filename = self.root_dir + './ts/src/test/static/markets/' + id + '.json'
657
+ filename = get_root_dir() + './ts/src/test/static/markets/' + id + '.json'
865
658
  content = io_file_read(filename)
866
659
  return content
867
660
 
868
661
  def load_currencies_from_file(self, id):
869
- filename = self.root_dir + './ts/src/test/static/currencies/' + id + '.json'
662
+ filename = get_root_dir() + './ts/src/test/static/currencies/' + id + '.json'
870
663
  content = io_file_read(filename)
871
664
  return content
872
665
 
@@ -923,7 +716,7 @@ class testMainClass(baseMainTestClass):
923
716
  result[key] = value
924
717
  return result
925
718
 
926
- def assert_new_and_stored_output(self, exchange, skip_keys, new_output, stored_output, strict_type_check=True, asserting_key=None):
719
+ def assert_new_and_stored_output_inner(self, exchange, skip_keys, new_output, stored_output, strict_type_check=True, asserting_key=None):
927
720
  if is_null_value(new_output) and is_null_value(stored_output):
928
721
  return True
929
722
  if not new_output and not stored_output:
@@ -964,9 +757,17 @@ class testMainClass(baseMainTestClass):
964
757
  # 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
965
758
  self.assert_static_error(sanitized_new_output == sanitized_stored_output, message_error, stored_output, new_output, asserting_key)
966
759
  else:
967
- is_boolean = (isinstance(sanitized_new_output, bool)) or (isinstance(sanitized_stored_output, bool))
968
- is_string = (isinstance(sanitized_new_output, str)) or (isinstance(sanitized_stored_output, str))
969
- is_undefined = (sanitized_new_output is None) or (sanitized_stored_output is None) # undefined is a perfetly valid value
760
+ is_computed_bool = (isinstance(sanitized_new_output, bool))
761
+ is_stored_bool = (isinstance(sanitized_stored_output, bool))
762
+ is_computed_string = (isinstance(sanitized_new_output, str))
763
+ is_stored_string = (isinstance(sanitized_stored_output, str))
764
+ is_computed_undefined = (sanitized_new_output is None)
765
+ is_stored_undefined = (sanitized_stored_output is None)
766
+ should_be_same = (is_computed_bool == is_stored_bool) and (is_computed_string == is_stored_string) and (is_computed_undefined == is_stored_undefined)
767
+ self.assert_static_error(should_be_same, 'output type mismatch', stored_output, new_output, asserting_key)
768
+ is_boolean = is_computed_bool or is_stored_bool
769
+ is_string = is_computed_string or is_stored_string
770
+ is_undefined = is_computed_undefined or is_stored_undefined # undefined is a perfetly valid value
970
771
  if is_boolean or is_string or is_undefined:
971
772
  if self.lang == 'C#':
972
773
  # tmp c# number comparsion
@@ -997,6 +798,25 @@ class testMainClass(baseMainTestClass):
997
798
  self.assert_static_error(numeric_new_output == numeric_stored_output, message_error, stored_output, new_output, asserting_key)
998
799
  return True # c# requ
999
800
 
801
+ def assert_new_and_stored_output(self, exchange, skip_keys, new_output, stored_output, strict_type_check=True, asserting_key=None):
802
+ try:
803
+ return self.assert_new_and_stored_output_inner(exchange, skip_keys, new_output, stored_output, strict_type_check, asserting_key)
804
+ except Exception as e:
805
+ if self.info:
806
+ error_message = self.var_to_string(new_output) + '(calculated)' + ' != ' + self.var_to_string(stored_output) + '(stored)'
807
+ dump('[TEST_FAILURE_DETAIL]' + error_message)
808
+ raise e
809
+
810
+ def var_to_string(self, obj=None):
811
+ new_string = None
812
+ if obj is None:
813
+ new_string = 'undefined'
814
+ elif is_null_value(obj):
815
+ new_string = 'null'
816
+ else:
817
+ new_string = json_stringify(obj)
818
+ return new_string
819
+
1000
820
  def assert_static_request_output(self, exchange, type, skip_keys, stored_url, request_url, stored_output, new_output):
1001
821
  if stored_url != request_url:
1002
822
  # remove the host part from the url
@@ -1052,13 +872,16 @@ class testMainClass(baseMainTestClass):
1052
872
  new_input.append(current)
1053
873
  return new_input
1054
874
 
1055
- async def test_method_statically(self, exchange, method, data, type, skip_keys):
875
+ async def test_request_statically(self, exchange, method, data, type, skip_keys):
1056
876
  output = None
1057
877
  request_url = None
1058
878
  try:
1059
- await call_exchange_method_dynamically(exchange, method, self.sanitize_data_input(data['input']))
879
+ if not is_sync():
880
+ await call_exchange_method_dynamically(exchange, method, self.sanitize_data_input(data['input']))
881
+ else:
882
+ call_exchange_method_dynamically_sync(exchange, method, self.sanitize_data_input(data['input']))
1060
883
  except Exception as e:
1061
- if not (isinstance(e, ProxyError)):
884
+ if not (isinstance(e, InvalidProxySettings)):
1062
885
  raise e
1063
886
  output = exchange.last_request_body
1064
887
  request_url = exchange.last_request_url
@@ -1067,18 +890,22 @@ class testMainClass(baseMainTestClass):
1067
890
  self.assert_static_request_output(exchange, type, skip_keys, data['url'], request_url, call_output, output)
1068
891
  except Exception as e:
1069
892
  self.request_tests_failed = True
1070
- error_message = '[' + self.lang + '][STATIC_REQUEST_TEST_FAILURE]' + '[' + self.exchange_hint(exchange) + ']' + '[' + method + ']' + '[' + data['description'] + ']' + str(e)
893
+ error_message = '[' + self.lang + '][STATIC_REQUEST]' + '[' + exchange.id + ']' + '[' + method + ']' + '[' + data['description'] + ']' + str(e)
1071
894
  dump('[TEST_FAILURE]' + error_message)
1072
895
 
1073
896
  async def test_response_statically(self, exchange, method, skip_keys, data):
1074
897
  expected_result = exchange.safe_value(data, 'parsedResponse')
1075
898
  mocked_exchange = set_fetch_response(exchange, data['httpResponse'])
1076
899
  try:
1077
- unified_result = await call_exchange_method_dynamically(exchange, method, self.sanitize_data_input(data['input']))
1078
- self.assert_static_response_output(mocked_exchange, skip_keys, unified_result, expected_result)
900
+ if not is_sync():
901
+ unified_result = await call_exchange_method_dynamically(exchange, method, self.sanitize_data_input(data['input']))
902
+ self.assert_static_response_output(mocked_exchange, skip_keys, unified_result, expected_result)
903
+ else:
904
+ unified_result_sync = call_exchange_method_dynamically_sync(exchange, method, self.sanitize_data_input(data['input']))
905
+ self.assert_static_response_output(mocked_exchange, skip_keys, unified_result_sync, expected_result)
1079
906
  except Exception as e:
1080
- self.request_tests_failed = True
1081
- error_message = '[' + self.lang + '][STATIC_RESPONSE_TEST_FAILURE]' + '[' + self.exchange_hint(exchange) + ']' + '[' + method + ']' + '[' + data['description'] + ']' + str(e)
907
+ self.response_tests_failed = True
908
+ error_message = '[' + self.lang + '][STATIC_RESPONSE]' + '[' + exchange.id + ']' + '[' + method + ']' + '[' + data['description'] + ']' + str(e)
1082
909
  dump('[TEST_FAILURE]' + error_message)
1083
910
  set_fetch_response(exchange, None) # reset state
1084
911
 
@@ -1099,6 +926,8 @@ class testMainClass(baseMainTestClass):
1099
926
  'privateKey': '0xff3bdd43534543d421f05aec535965b5050ad6ac15345435345435453495e771',
1100
927
  'uid': 'uid',
1101
928
  'token': 'token',
929
+ 'login': 'login',
930
+ 'accountId': 'accountId',
1102
931
  'accounts': [{
1103
932
  'id': 'myAccount',
1104
933
  'code': 'USDT',
@@ -1121,7 +950,24 @@ class testMainClass(baseMainTestClass):
1121
950
  # instantiate the exchange and make sure that we sink the requests to avoid an actual request
1122
951
  exchange = self.init_offline_exchange(exchange_name)
1123
952
  global_options = exchange.safe_dict(exchange_data, 'options', {})
1124
- exchange.options = exchange.deep_extend(exchange.options, global_options) # custom options to be used in the tests
953
+ # read apiKey/secret from the test file
954
+ api_key = exchange.safe_string(exchange_data, 'apiKey')
955
+ if api_key:
956
+ exchange.apiKey = str(api_key)
957
+ secret = exchange.safe_string(exchange_data, 'secret')
958
+ if secret:
959
+ exchange.secret = str(secret)
960
+ private_key = exchange.safe_string(exchange_data, 'privateKey')
961
+ if private_key:
962
+ exchange.privateKey = str(private_key)
963
+ wallet_address = exchange.safe_string(exchange_data, 'walletAddress')
964
+ if wallet_address:
965
+ exchange.walletAddress = str(wallet_address)
966
+ accounts = exchange.safe_list(exchange_data, 'accounts')
967
+ if accounts:
968
+ exchange.accounts = accounts
969
+ # exchange.options = exchange.deepExtend (exchange.options, globalOptions); # custom options to be used in the tests
970
+ exchange.extend_exchange_options(global_options)
1125
971
  methods = exchange.safe_value(exchange_data, 'methods', {})
1126
972
  methods_names = list(methods.keys())
1127
973
  for i in range(0, len(methods_names)):
@@ -1131,26 +977,49 @@ class testMainClass(baseMainTestClass):
1131
977
  result = results[j]
1132
978
  old_exchange_options = exchange.options # snapshot options;
1133
979
  test_exchange_options = exchange.safe_value(result, 'options', {})
1134
- exchange.options = exchange.deep_extend(old_exchange_options, test_exchange_options) # custom options to be used in the tests
980
+ # exchange.options = exchange.deepExtend (oldExchangeOptions, testExchangeOptions); # custom options to be used in the tests
981
+ exchange.extend_exchange_options(exchange.deep_extend(old_exchange_options, test_exchange_options))
1135
982
  description = exchange.safe_value(result, 'description')
1136
983
  if (test_name is not None) and (test_name != description):
1137
984
  continue
1138
985
  is_disabled = exchange.safe_bool(result, 'disabled', False)
1139
986
  if is_disabled:
1140
987
  continue
988
+ disabled_string = exchange.safe_string(result, 'disabled', '')
989
+ if disabled_string != '':
990
+ continue
991
+ is_disabled_c_sharp = exchange.safe_bool(result, 'disabledCS', False)
992
+ if is_disabled_c_sharp and (self.lang == 'C#'):
993
+ continue
1141
994
  type = exchange.safe_string(exchange_data, 'outputType')
1142
995
  skip_keys = exchange.safe_value(exchange_data, 'skipKeys', [])
1143
- await self.test_method_statically(exchange, method, result, type, skip_keys)
996
+ await self.test_request_statically(exchange, method, result, type, skip_keys)
1144
997
  # reset options
1145
- exchange.options = exchange.deep_extend(old_exchange_options, {})
1146
- await close(exchange)
998
+ # exchange.options = exchange.deepExtend (oldExchangeOptions, {});
999
+ exchange.extend_exchange_options(exchange.deep_extend(old_exchange_options, {}))
1000
+ if not is_sync():
1001
+ await close(exchange)
1147
1002
  return True # in c# methods that will be used with promiseAll need to return something
1148
1003
 
1149
1004
  async def test_exchange_response_statically(self, exchange_name, exchange_data, test_name=None):
1150
1005
  exchange = self.init_offline_exchange(exchange_name)
1006
+ # read apiKey/secret from the test file
1007
+ api_key = exchange.safe_string(exchange_data, 'apiKey')
1008
+ if api_key:
1009
+ exchange.apiKey = str(api_key)
1010
+ secret = exchange.safe_string(exchange_data, 'secret')
1011
+ if secret:
1012
+ exchange.secret = str(secret)
1013
+ private_key = exchange.safe_string(exchange_data, 'privateKey')
1014
+ if private_key:
1015
+ exchange.privateKey = str(private_key)
1016
+ wallet_address = exchange.safe_string(exchange_data, 'walletAddress')
1017
+ if wallet_address:
1018
+ exchange.walletAddress = str(wallet_address)
1151
1019
  methods = exchange.safe_value(exchange_data, 'methods', {})
1152
1020
  options = exchange.safe_value(exchange_data, 'options', {})
1153
- exchange.options = exchange.deep_extend(exchange.options, options) # custom options to be used in the tests
1021
+ # exchange.options = exchange.deepExtend (exchange.options, options); # custom options to be used in the tests
1022
+ exchange.extend_exchange_options(options)
1154
1023
  methods_names = list(methods.keys())
1155
1024
  for i in range(0, len(methods_names)):
1156
1025
  method = methods_names[i]
@@ -1160,7 +1029,8 @@ class testMainClass(baseMainTestClass):
1160
1029
  description = exchange.safe_value(result, 'description')
1161
1030
  old_exchange_options = exchange.options # snapshot options;
1162
1031
  test_exchange_options = exchange.safe_value(result, 'options', {})
1163
- exchange.options = exchange.deep_extend(old_exchange_options, test_exchange_options) # custom options to be used in the tests
1032
+ # exchange.options = exchange.deepExtend (oldExchangeOptions, testExchangeOptions); # custom options to be used in the tests
1033
+ exchange.extend_exchange_options(exchange.deep_extend(old_exchange_options, test_exchange_options))
1164
1034
  is_disabled = exchange.safe_bool(result, 'disabled', False)
1165
1035
  if is_disabled:
1166
1036
  continue
@@ -1175,8 +1045,10 @@ class testMainClass(baseMainTestClass):
1175
1045
  skip_keys = exchange.safe_value(exchange_data, 'skipKeys', [])
1176
1046
  await self.test_response_statically(exchange, method, skip_keys, result)
1177
1047
  # reset options
1178
- exchange.options = exchange.deep_extend(old_exchange_options, {})
1179
- await close(exchange)
1048
+ # exchange.options = exchange.deepExtend (oldExchangeOptions, {});
1049
+ exchange.extend_exchange_options(exchange.deep_extend(old_exchange_options, {}))
1050
+ if not is_sync():
1051
+ await close(exchange)
1180
1052
  return True # in c# methods that will be used with promiseAll need to return something
1181
1053
 
1182
1054
  def get_number_of_tests_from_exchange(self, exchange, exchange_data, test_name=None):
@@ -1196,7 +1068,7 @@ class testMainClass(baseMainTestClass):
1196
1068
  await self.run_static_tests('request', target_exchange, test_name)
1197
1069
 
1198
1070
  async def run_static_tests(self, type, target_exchange=None, test_name=None):
1199
- folder = self.root_dir + './ts/src/test/static/' + type + '/'
1071
+ folder = get_root_dir() + './ts/src/test/static/' + type + '/'
1200
1072
  static_data = self.load_static_data(folder, target_exchange)
1201
1073
  if static_data is None:
1202
1074
  return
@@ -1217,11 +1089,20 @@ class testMainClass(baseMainTestClass):
1217
1089
  promises.append(self.test_exchange_request_statically(exchange_name, exchange_data, test_name))
1218
1090
  else:
1219
1091
  promises.append(self.test_exchange_response_statically(exchange_name, exchange_data, test_name))
1220
- await asyncio.gather(*promises)
1092
+ try:
1093
+ await asyncio.gather(*promises)
1094
+ except Exception as e:
1095
+ if type == 'request':
1096
+ self.request_tests_failed = True
1097
+ else:
1098
+ self.response_tests_failed = True
1099
+ error_message = '[' + self.lang + '][STATIC_REQUEST]' + str(e)
1100
+ dump('[TEST_FAILURE]' + error_message)
1221
1101
  if self.request_tests_failed or self.response_tests_failed:
1222
1102
  exit_script(1)
1223
1103
  else:
1224
- success_message = '[' + self.lang + '][TEST_SUCCESS] ' + str(sum) + ' static ' + type + ' tests passed.'
1104
+ prefix = '[SYNC]' if (is_sync()) else ''
1105
+ success_message = '[' + self.lang + ']' + prefix + '[TEST_SUCCESS] ' + str(sum) + ' static ' + type + ' tests passed.'
1225
1106
  dump('[INFO]' + success_message)
1226
1107
 
1227
1108
  async def run_static_response_tests(self, exchange_name=None, test=None):
@@ -1234,7 +1115,7 @@ class testMainClass(baseMainTestClass):
1234
1115
  # -----------------------------------------------------------------------------
1235
1116
  # --- Init of brokerId tests functions-----------------------------------------
1236
1117
  # -----------------------------------------------------------------------------
1237
- 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()]
1118
+ 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()]
1238
1119
  await asyncio.gather(*promises)
1239
1120
  success_message = '[' + self.lang + '][TEST_SUCCESS] brokerId tests passed.'
1240
1121
  dump('[INFO]' + success_message)
@@ -1267,7 +1148,8 @@ class testMainClass(baseMainTestClass):
1267
1148
  assert client_order_id_swap.startswith(swap_id_string), 'binance - swap clientOrderId: ' + client_order_id_swap + ' does not start with swapId' + swap_id_string
1268
1149
  client_order_id_inverse = swap_inverse_order_request['newClientOrderId']
1269
1150
  assert client_order_id_inverse.startswith(swap_id_string), 'binance - swap clientOrderIdInverse: ' + client_order_id_inverse + ' does not start with swapId' + swap_id_string
1270
- await close(exchange)
1151
+ if not is_sync():
1152
+ await close(exchange)
1271
1153
  return True
1272
1154
 
1273
1155
  async def test_okx(self):
@@ -1292,7 +1174,8 @@ class testMainClass(baseMainTestClass):
1292
1174
  assert client_order_id_swap.startswith(id_string), 'okx - swap clientOrderId: ' + client_order_id_swap + ' does not start with id: ' + id_string
1293
1175
  swap_tag = swap_order_request[0]['tag']
1294
1176
  assert swap_tag == id, 'okx - id: ' + id + ' different from swap tag: ' + swap_tag
1295
- await close(exchange)
1177
+ if not is_sync():
1178
+ await close(exchange)
1296
1179
  return True
1297
1180
 
1298
1181
  async def test_cryptocom(self):
@@ -1306,7 +1189,8 @@ class testMainClass(baseMainTestClass):
1306
1189
  request = json_parse(exchange.last_request_body)
1307
1190
  broker_id = request['params']['broker_id']
1308
1191
  assert broker_id == id, 'cryptocom - id: ' + id + ' different from broker_id: ' + broker_id
1309
- await close(exchange)
1192
+ if not is_sync():
1193
+ await close(exchange)
1310
1194
  return True
1311
1195
 
1312
1196
  async def test_bybit(self):
@@ -1320,17 +1204,17 @@ class testMainClass(baseMainTestClass):
1320
1204
  # we expect an error here, we're only interested in the headers
1321
1205
  req_headers = exchange.last_request_headers
1322
1206
  assert req_headers['Referer'] == id, 'bybit - id: ' + id + ' not in headers.'
1323
- await close(exchange)
1207
+ if not is_sync():
1208
+ await close(exchange)
1324
1209
  return True
1325
1210
 
1326
1211
  async def test_kucoin(self):
1327
1212
  exchange = self.init_offline_exchange('kucoin')
1328
1213
  req_headers = None
1329
- options_string = str(exchange.options)
1330
1214
  spot_id = exchange.options['partner']['spot']['id']
1331
1215
  spot_key = exchange.options['partner']['spot']['key']
1332
- assert spot_id == 'ccxt', 'kucoin - id: ' + spot_id + ' not in options: ' + options_string
1333
- assert spot_key == '9e58cc35-5b5e-4133-92ec-166e3f077cb8', 'kucoin - key: ' + spot_key + ' not in options: ' + options_string
1216
+ assert spot_id == 'ccxt', 'kucoin - id: ' + spot_id + ' not in options'
1217
+ assert spot_key == '9e58cc35-5b5e-4133-92ec-166e3f077cb8', 'kucoin - key: ' + spot_key + ' not in options.'
1334
1218
  try:
1335
1219
  await exchange.create_order('BTC/USDT', 'limit', 'buy', 1, 20000)
1336
1220
  except Exception as e:
@@ -1338,54 +1222,54 @@ class testMainClass(baseMainTestClass):
1338
1222
  req_headers = exchange.last_request_headers
1339
1223
  id = 'ccxt'
1340
1224
  assert req_headers['KC-API-PARTNER'] == id, 'kucoin - id: ' + id + ' not in headers.'
1341
- await close(exchange)
1225
+ if not is_sync():
1226
+ await close(exchange)
1342
1227
  return True
1343
1228
 
1344
1229
  async def test_kucoinfutures(self):
1345
1230
  exchange = self.init_offline_exchange('kucoinfutures')
1346
1231
  req_headers = None
1347
1232
  id = 'ccxtfutures'
1348
- options_string = str(exchange.options['partner']['future'])
1349
1233
  future_id = exchange.options['partner']['future']['id']
1350
1234
  future_key = exchange.options['partner']['future']['key']
1351
- assert future_id == id, 'kucoinfutures - id: ' + future_id + ' not in options: ' + options_string
1352
- assert future_key == '1b327198-f30c-4f14-a0ac-918871282f15', 'kucoinfutures - key: ' + future_key + ' not in options: ' + options_string
1235
+ assert future_id == id, 'kucoinfutures - id: ' + future_id + ' not in options.'
1236
+ assert future_key == '1b327198-f30c-4f14-a0ac-918871282f15', 'kucoinfutures - key: ' + future_key + ' not in options.'
1353
1237
  try:
1354
1238
  await exchange.create_order('BTC/USDT:USDT', 'limit', 'buy', 1, 20000)
1355
1239
  except Exception as e:
1356
1240
  req_headers = exchange.last_request_headers
1357
1241
  assert req_headers['KC-API-PARTNER'] == id, 'kucoinfutures - id: ' + id + ' not in headers.'
1358
- await close(exchange)
1242
+ if not is_sync():
1243
+ await close(exchange)
1359
1244
  return True
1360
1245
 
1361
1246
  async def test_bitget(self):
1362
1247
  exchange = self.init_offline_exchange('bitget')
1363
1248
  req_headers = None
1364
1249
  id = 'p4sve'
1365
- options_string = str(exchange.options)
1366
- assert exchange.options['broker'] == id, 'bitget - id: ' + id + ' not in options: ' + options_string
1250
+ assert exchange.options['broker'] == id, 'bitget - id: ' + id + ' not in options'
1367
1251
  try:
1368
1252
  await exchange.create_order('BTC/USDT', 'limit', 'buy', 1, 20000)
1369
1253
  except Exception as e:
1370
1254
  req_headers = exchange.last_request_headers
1371
1255
  assert req_headers['X-CHANNEL-API-CODE'] == id, 'bitget - id: ' + id + ' not in headers.'
1372
- await close(exchange)
1256
+ if not is_sync():
1257
+ await close(exchange)
1373
1258
  return True
1374
1259
 
1375
1260
  async def test_mexc(self):
1376
1261
  exchange = self.init_offline_exchange('mexc')
1377
1262
  req_headers = None
1378
1263
  id = 'CCXT'
1379
- options_string = str(exchange.options)
1380
- assert exchange.options['broker'] == id, 'mexc - id: ' + id + ' not in options: ' + options_string
1264
+ assert exchange.options['broker'] == id, 'mexc - id: ' + id + ' not in options'
1381
1265
  await exchange.load_markets()
1382
1266
  try:
1383
1267
  await exchange.create_order('BTC/USDT', 'limit', 'buy', 1, 20000)
1384
1268
  except Exception as e:
1385
1269
  req_headers = exchange.last_request_headers
1386
- req_headers_string = str(req_headers) if req_headers is not None else 'undefined'
1387
- assert req_headers['source'] == id, 'mexc - id: ' + id + ' not in headers: ' + req_headers_string
1388
- await close(exchange)
1270
+ assert req_headers['source'] == id, 'mexc - id: ' + id + ' not in headers.'
1271
+ if not is_sync():
1272
+ await close(exchange)
1389
1273
  return True
1390
1274
 
1391
1275
  async def test_htx(self):
@@ -1415,7 +1299,8 @@ class testMainClass(baseMainTestClass):
1415
1299
  assert client_order_id_swap.startswith(id_string), 'htx - swap channel_code ' + client_order_id_swap + ' does not start with id: ' + id_string
1416
1300
  client_order_id_inverse = swap_inverse_order_request['channel_code']
1417
1301
  assert client_order_id_inverse.startswith(id_string), 'htx - swap inverse channel_code ' + client_order_id_inverse + ' does not start with id: ' + id_string
1418
- await close(exchange)
1302
+ if not is_sync():
1303
+ await close(exchange)
1419
1304
  return True
1420
1305
 
1421
1306
  async def test_woo(self):
@@ -1440,7 +1325,8 @@ class testMainClass(baseMainTestClass):
1440
1325
  stop_order_request = json_parse(exchange.last_request_body)
1441
1326
  client_order_id_stop = stop_order_request['brokerId']
1442
1327
  assert client_order_id_stop.startswith(id_string), 'woo - brokerId: ' + client_order_id_stop + ' does not start with id: ' + id_string
1443
- await close(exchange)
1328
+ if not is_sync():
1329
+ await close(exchange)
1444
1330
  return True
1445
1331
 
1446
1332
  async def test_bitmart(self):
@@ -1454,7 +1340,8 @@ class testMainClass(baseMainTestClass):
1454
1340
  except Exception as e:
1455
1341
  req_headers = exchange.last_request_headers
1456
1342
  assert req_headers['X-BM-BROKER-ID'] == id, 'bitmart - id: ' + id + ' not in headers'
1457
- await close(exchange)
1343
+ if not is_sync():
1344
+ await close(exchange)
1458
1345
  return True
1459
1346
 
1460
1347
  async def test_coinex(self):
@@ -1469,23 +1356,23 @@ class testMainClass(baseMainTestClass):
1469
1356
  client_order_id = spot_order_request['client_id']
1470
1357
  id_string = str(id)
1471
1358
  assert client_order_id.startswith(id_string), 'coinex - clientOrderId: ' + client_order_id + ' does not start with id: ' + id_string
1472
- await close(exchange)
1359
+ if not is_sync():
1360
+ await close(exchange)
1473
1361
  return True
1474
1362
 
1475
1363
  async def test_bingx(self):
1476
1364
  exchange = self.init_offline_exchange('bingx')
1477
1365
  req_headers = None
1478
1366
  id = 'CCXT'
1479
- options_string = str(exchange.options)
1480
- assert exchange.options['broker'] == id, 'bingx - id: ' + id + ' not in options: ' + options_string
1367
+ assert exchange.options['broker'] == id, 'bingx - id: ' + id + ' not in options'
1481
1368
  try:
1482
1369
  await exchange.create_order('BTC/USDT', 'limit', 'buy', 1, 20000)
1483
1370
  except Exception as e:
1484
1371
  # we expect an error here, we're only interested in the headers
1485
1372
  req_headers = exchange.last_request_headers
1486
- req_headers_string = str(req_headers) if req_headers is not None else 'undefined'
1487
- assert req_headers['X-SOURCE-KEY'] == id, 'bingx - id: ' + id + ' not in headers: ' + req_headers_string
1488
- await close(exchange)
1373
+ assert req_headers['X-SOURCE-KEY'] == id, 'bingx - id: ' + id + ' not in headers.'
1374
+ if not is_sync():
1375
+ await close(exchange)
1489
1376
 
1490
1377
  async def test_phemex(self):
1491
1378
  exchange = self.init_offline_exchange('phemex')
@@ -1498,7 +1385,8 @@ class testMainClass(baseMainTestClass):
1498
1385
  client_order_id = request['clOrdID']
1499
1386
  id_string = str(id)
1500
1387
  assert client_order_id.startswith(id_string), 'phemex - clOrdID: ' + client_order_id + ' does not start with id: ' + id_string
1501
- await close(exchange)
1388
+ if not is_sync():
1389
+ await close(exchange)
1502
1390
 
1503
1391
  async def test_blofin(self):
1504
1392
  exchange = self.init_offline_exchange('blofin')
@@ -1511,7 +1399,8 @@ class testMainClass(baseMainTestClass):
1511
1399
  broker_id = request['brokerId']
1512
1400
  id_string = str(id)
1513
1401
  assert broker_id.startswith(id_string), 'blofin - brokerId: ' + broker_id + ' does not start with id: ' + id_string
1514
- await close(exchange)
1402
+ if not is_sync():
1403
+ await close(exchange)
1515
1404
 
1516
1405
  async def test_hyperliquid(self):
1517
1406
  exchange = self.init_offline_exchange('hyperliquid')
@@ -1523,7 +1412,8 @@ class testMainClass(baseMainTestClass):
1523
1412
  request = json_parse(exchange.last_request_body)
1524
1413
  broker_id = str((request['action']['brokerCode']))
1525
1414
  assert broker_id == id, 'hyperliquid - brokerId: ' + broker_id + ' does not start with id: ' + id
1526
- await close(exchange)
1415
+ if not is_sync():
1416
+ await close(exchange)
1527
1417
 
1528
1418
  async def test_coinbaseinternational(self):
1529
1419
  exchange = self.init_offline_exchange('coinbaseinternational')
@@ -1537,13 +1427,181 @@ class testMainClass(baseMainTestClass):
1537
1427
  request = json_parse(exchange.last_request_body)
1538
1428
  client_order_id = request['client_order_id']
1539
1429
  assert client_order_id.startswith(str(id)), 'clientOrderId does not start with id'
1540
- await close(exchange)
1430
+ if not is_sync():
1431
+ await close(exchange)
1432
+ return True
1433
+
1434
+ async def test_coinbase_advanced(self):
1435
+ exchange = self.init_offline_exchange('coinbase')
1436
+ id = 'ccxt'
1437
+ assert exchange.options['brokerId'] == id, 'id not in options'
1438
+ request = None
1439
+ try:
1440
+ await exchange.create_order('BTC/USDC', 'limit', 'buy', 1, 20000)
1441
+ except Exception as e:
1442
+ request = json_parse(exchange.last_request_body)
1443
+ client_order_id = request['client_order_id']
1444
+ assert client_order_id.startswith(str(id)), 'clientOrderId does not start with id'
1445
+ if not is_sync():
1446
+ await close(exchange)
1541
1447
  return True
1542
1448
 
1543
- # ***** AUTO-TRANSPILER-END *****
1544
- # *******************************
1449
+ async def test_woofi_pro(self):
1450
+ exchange = self.init_offline_exchange('woofipro')
1451
+ exchange.secret = 'secretsecretsecretsecretsecretsecretsecrets'
1452
+ id = 'CCXT'
1453
+ await exchange.load_markets()
1454
+ request = None
1455
+ try:
1456
+ await exchange.create_order('BTC/USDC:USDC', 'limit', 'buy', 1, 20000)
1457
+ except Exception as e:
1458
+ request = json_parse(exchange.last_request_body)
1459
+ broker_id = request['order_tag']
1460
+ assert broker_id == id, 'woofipro - id: ' + id + ' different from broker_id: ' + broker_id
1461
+ if not is_sync():
1462
+ await close(exchange)
1463
+ return True
1545
1464
 
1465
+ async def test_oxfun(self):
1466
+ exchange = self.init_offline_exchange('oxfun')
1467
+ exchange.secret = 'secretsecretsecretsecretsecretsecretsecrets'
1468
+ id = 1000
1469
+ await exchange.load_markets()
1470
+ request = None
1471
+ try:
1472
+ await exchange.create_order('BTC/USD:OX', 'limit', 'buy', 1, 20000)
1473
+ except Exception as e:
1474
+ request = json_parse(exchange.last_request_body)
1475
+ orders = request['orders']
1476
+ first = orders[0]
1477
+ broker_id = first['source']
1478
+ assert broker_id == id, 'oxfun - id: ' + str(id) + ' different from broker_id: ' + str(broker_id)
1479
+ return True
1546
1480
 
1547
- if __name__ == '__main__':
1548
- symbol = argv.symbol if argv.symbol else None
1549
- asyncio.run(testMainClass().init(argv.exchange, symbol))
1481
+ async def test_xt(self):
1482
+ exchange = self.init_offline_exchange('xt')
1483
+ id = 'CCXT'
1484
+ spot_order_request = None
1485
+ try:
1486
+ await exchange.create_order('BTC/USDT', 'limit', 'buy', 1, 20000)
1487
+ except Exception as e:
1488
+ spot_order_request = json_parse(exchange.last_request_body)
1489
+ spot_media = spot_order_request['media']
1490
+ assert spot_media == id, 'xt - id: ' + id + ' different from swap tag: ' + spot_media
1491
+ swap_order_request = None
1492
+ try:
1493
+ await exchange.create_order('BTC/USDT:USDT', 'limit', 'buy', 1, 20000)
1494
+ except Exception as e:
1495
+ swap_order_request = json_parse(exchange.last_request_body)
1496
+ swap_media = swap_order_request['clientMedia']
1497
+ assert swap_media == id, 'xt - id: ' + id + ' different from swap tag: ' + swap_media
1498
+ if not is_sync():
1499
+ await close(exchange)
1500
+ return True
1501
+
1502
+ async def test_vertex(self):
1503
+ exchange = self.init_offline_exchange('vertex')
1504
+ exchange.walletAddress = '0xc751489d24a33172541ea451bc253d7a9e98c781'
1505
+ exchange.privateKey = 'c33b1eb4b53108bf52e10f636d8c1236c04c33a712357ba3543ab45f48a5cb0b'
1506
+ exchange.options['v1contracts'] = {
1507
+ 'chain_id': '42161',
1508
+ 'endpoint_addr': '0xbbee07b3e8121227afcfe1e2b82772246226128e',
1509
+ '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'],
1510
+ }
1511
+ id = 5930043274845996
1512
+ await exchange.load_markets()
1513
+ request = None
1514
+ try:
1515
+ await exchange.create_order('BTC/USDC:USDC', 'limit', 'buy', 1, 20000)
1516
+ except Exception as e:
1517
+ request = json_parse(exchange.last_request_body)
1518
+ order = request['place_order']
1519
+ broker_id = order['id']
1520
+ assert broker_id == id, 'vertex - id: ' + str(id) + ' different from broker_id: ' + str(broker_id)
1521
+ if not is_sync():
1522
+ await close(exchange)
1523
+ return True
1524
+
1525
+ async def test_paradex(self):
1526
+ exchange = self.init_offline_exchange('paradex')
1527
+ exchange.walletAddress = '0xc751489d24a33172541ea451bc253d7a9e98c781'
1528
+ exchange.privateKey = 'c33b1eb4b53108bf52e10f636d8c1236c04c33a712357ba3543ab45f48a5cb0b'
1529
+ exchange.options['authToken'] = 'token'
1530
+ exchange.options['systemConfig'] = {
1531
+ 'starknet_gateway_url': 'https://potc-testnet-sepolia.starknet.io',
1532
+ 'starknet_fullnode_rpc_url': 'https://pathfinder.api.testnet.paradex.trade/rpc/v0_7',
1533
+ 'starknet_chain_id': 'PRIVATE_SN_POTC_SEPOLIA',
1534
+ 'block_explorer_url': 'https://voyager.testnet.paradex.trade/',
1535
+ 'paraclear_address': '0x286003f7c7bfc3f94e8f0af48b48302e7aee2fb13c23b141479ba00832ef2c6',
1536
+ 'paraclear_decimals': 8,
1537
+ 'paraclear_account_proxy_hash': '0x3530cc4759d78042f1b543bf797f5f3d647cde0388c33734cf91b7f7b9314a9',
1538
+ 'paraclear_account_hash': '0x41cb0280ebadaa75f996d8d92c6f265f6d040bb3ba442e5f86a554f1765244e',
1539
+ 'oracle_address': '0x2c6a867917ef858d6b193a0ff9e62b46d0dc760366920d631715d58baeaca1f',
1540
+ 'bridged_tokens': [{
1541
+ 'name': 'TEST USDC',
1542
+ 'symbol': 'USDC',
1543
+ 'decimals': 6,
1544
+ 'l1_token_address': '0x29A873159D5e14AcBd63913D4A7E2df04570c666',
1545
+ 'l1_bridge_address': '0x8586e05adc0C35aa11609023d4Ae6075Cb813b4C',
1546
+ 'l2_token_address': '0x6f373b346561036d98ea10fb3e60d2f459c872b1933b50b21fe6ef4fda3b75e',
1547
+ 'l2_bridge_address': '0x46e9237f5408b5f899e72125dd69bd55485a287aaf24663d3ebe00d237fc7ef',
1548
+ }],
1549
+ 'l1_core_contract_address': '0x582CC5d9b509391232cd544cDF9da036e55833Af',
1550
+ 'l1_operator_address': '0x11bACdFbBcd3Febe5e8CEAa75E0Ef6444d9B45FB',
1551
+ 'l1_chain_id': '11155111',
1552
+ 'liquidation_fee': '0.2',
1553
+ }
1554
+ req_headers = None
1555
+ id = 'CCXT'
1556
+ assert exchange.options['broker'] == id, 'paradex - id: ' + id + ' not in options'
1557
+ await exchange.load_markets()
1558
+ try:
1559
+ await exchange.create_order('BTC/USD:USDC', 'limit', 'buy', 1, 20000)
1560
+ except Exception as e:
1561
+ req_headers = exchange.last_request_headers
1562
+ assert req_headers['PARADEX-PARTNER'] == id, 'paradex - id: ' + id + ' not in headers'
1563
+ if not is_sync():
1564
+ await close(exchange)
1565
+ return True
1566
+
1567
+ async def test_hashkey(self):
1568
+ exchange = self.init_offline_exchange('hashkey')
1569
+ req_headers = None
1570
+ id = '10000700011'
1571
+ try:
1572
+ await exchange.create_order('BTC/USDT', 'limit', 'buy', 1, 20000)
1573
+ except Exception as e:
1574
+ # we expect an error here, we're only interested in the headers
1575
+ req_headers = exchange.last_request_headers
1576
+ assert req_headers['INPUT-SOURCE'] == id, 'hashkey - id: ' + id + ' not in headers.'
1577
+ if not is_sync():
1578
+ await close(exchange)
1579
+ return True
1580
+
1581
+ async def test_coincatch(self):
1582
+ exchange = self.init_offline_exchange('coincatch')
1583
+ req_headers = None
1584
+ id = '47cfy'
1585
+ try:
1586
+ await exchange.create_order('BTC/USDT', 'limit', 'buy', 1, 20000)
1587
+ except Exception as e:
1588
+ # we expect an error here, we're only interested in the headers
1589
+ req_headers = exchange.last_request_headers
1590
+ assert req_headers['X-CHANNEL-API-CODE'] == id, 'coincatch - id: ' + id + ' not in headers.'
1591
+ if not is_sync():
1592
+ await close(exchange)
1593
+ return True
1594
+
1595
+ async def test_defx(self):
1596
+ exchange = self.init_offline_exchange('defx')
1597
+ req_headers = None
1598
+ try:
1599
+ await exchange.create_order('DOGE/USDC:USDC', 'limit', 'buy', 100, 1)
1600
+ except Exception as e:
1601
+ # we expect an error here, we're only interested in the headers
1602
+ req_headers = exchange.last_request_headers
1603
+ id = 'ccxt'
1604
+ assert req_headers['X-DEFX-SOURCE'] == id, 'defx - id: ' + id + ' not in headers.'
1605
+ if not is_sync():
1606
+ await close(exchange)
1607
+ return True