ccxt 4.2.77__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.
- ccxt/__init__.py +36 -14
- ccxt/abstract/alpaca.py +4 -0
- ccxt/abstract/bigone.py +1 -1
- ccxt/abstract/binance.py +112 -48
- ccxt/abstract/binancecoinm.py +112 -48
- ccxt/abstract/binanceus.py +147 -83
- ccxt/abstract/binanceusdm.py +112 -48
- ccxt/abstract/bingx.py +133 -78
- ccxt/abstract/bitbank.py +5 -0
- ccxt/abstract/bitfinex.py +136 -65
- ccxt/abstract/bitfinex1.py +69 -0
- ccxt/abstract/bitflyer.py +1 -0
- ccxt/abstract/bitget.py +8 -1
- ccxt/abstract/bitmart.py +13 -1
- ccxt/abstract/bitopro.py +1 -0
- ccxt/abstract/bitpanda.py +0 -12
- ccxt/abstract/bitrue.py +3 -3
- ccxt/abstract/bitstamp.py +26 -3
- ccxt/abstract/blofin.py +24 -0
- ccxt/abstract/btcbox.py +1 -0
- ccxt/abstract/bybit.py +29 -14
- ccxt/abstract/cex.py +28 -29
- ccxt/abstract/coinbase.py +6 -0
- ccxt/abstract/coinbaseadvanced.py +94 -0
- ccxt/abstract/{coinbasepro.py → coinbaseexchange.py} +1 -0
- ccxt/abstract/coinbaseinternational.py +1 -1
- ccxt/abstract/coincatch.py +94 -0
- ccxt/abstract/coinex.py +233 -123
- ccxt/abstract/coinmetro.py +1 -0
- ccxt/abstract/cryptocom.py +14 -0
- ccxt/abstract/defx.py +69 -0
- ccxt/abstract/deribit.py +1 -0
- ccxt/abstract/digifinex.py +1 -0
- ccxt/abstract/ellipx.py +25 -0
- ccxt/abstract/gate.py +20 -0
- ccxt/abstract/gateio.py +20 -0
- ccxt/abstract/gemini.py +1 -0
- ccxt/abstract/hashkey.py +67 -0
- ccxt/abstract/hyperliquid.py +1 -1
- ccxt/abstract/independentreserve.py +6 -0
- ccxt/abstract/kraken.py +4 -3
- ccxt/abstract/krakenfutures.py +4 -0
- ccxt/abstract/kucoin.py +24 -0
- ccxt/abstract/kucoinfutures.py +34 -0
- ccxt/abstract/luno.py +2 -0
- ccxt/abstract/mexc.py +4 -0
- ccxt/abstract/myokx.py +340 -0
- ccxt/abstract/oceanex.py +5 -0
- ccxt/abstract/okx.py +30 -0
- ccxt/abstract/onetrading.py +0 -12
- ccxt/abstract/oxfun.py +34 -0
- ccxt/abstract/paradex.py +40 -0
- ccxt/abstract/phemex.py +1 -0
- ccxt/abstract/upbit.py +4 -0
- ccxt/abstract/vertex.py +19 -0
- ccxt/abstract/whitebit.py +31 -1
- ccxt/abstract/woo.py +6 -2
- ccxt/abstract/woofipro.py +119 -0
- ccxt/abstract/xt.py +153 -0
- ccxt/abstract/zonda.py +6 -0
- ccxt/ace.py +164 -60
- ccxt/alpaca.py +727 -63
- ccxt/ascendex.py +395 -249
- ccxt/async_support/__init__.py +36 -14
- ccxt/async_support/ace.py +164 -60
- ccxt/async_support/alpaca.py +727 -63
- ccxt/async_support/ascendex.py +396 -249
- ccxt/async_support/base/exchange.py +531 -155
- ccxt/async_support/base/ws/aiohttp_client.py +28 -5
- ccxt/async_support/base/ws/cache.py +3 -2
- ccxt/async_support/base/ws/client.py +26 -5
- ccxt/async_support/base/ws/fast_client.py +4 -3
- ccxt/async_support/base/ws/functions.py +1 -1
- ccxt/async_support/base/ws/future.py +40 -31
- ccxt/async_support/base/ws/order_book_side.py +3 -0
- ccxt/async_support/bequant.py +1 -1
- ccxt/async_support/bigone.py +329 -202
- ccxt/async_support/binance.py +3030 -1087
- ccxt/async_support/binancecoinm.py +2 -1
- ccxt/async_support/binanceus.py +12 -1
- ccxt/async_support/binanceusdm.py +3 -1
- ccxt/async_support/bingx.py +3104 -880
- ccxt/async_support/bit2c.py +119 -38
- ccxt/async_support/bitbank.py +215 -76
- ccxt/async_support/bitbns.py +124 -53
- ccxt/async_support/bitfinex.py +3236 -1078
- ccxt/async_support/bitfinex1.py +1711 -0
- ccxt/async_support/bitflyer.py +238 -49
- ccxt/async_support/bitget.py +1513 -563
- ccxt/async_support/bithumb.py +199 -65
- ccxt/async_support/bitmart.py +1320 -435
- ccxt/async_support/bitmex.py +308 -111
- ccxt/async_support/bitopro.py +256 -96
- ccxt/async_support/bitrue.py +365 -233
- ccxt/async_support/bitso.py +201 -89
- ccxt/async_support/bitstamp.py +438 -269
- ccxt/async_support/bitteam.py +179 -73
- ccxt/async_support/bitvavo.py +180 -70
- ccxt/async_support/bl3p.py +92 -25
- ccxt/async_support/blockchaincom.py +193 -79
- ccxt/async_support/blofin.py +392 -148
- ccxt/async_support/btcalpha.py +161 -55
- ccxt/async_support/btcbox.py +250 -34
- ccxt/async_support/btcmarkets.py +232 -85
- ccxt/async_support/btcturk.py +159 -60
- ccxt/async_support/bybit.py +2231 -1193
- ccxt/async_support/cex.py +1409 -1329
- ccxt/async_support/coinbase.py +1454 -287
- ccxt/async_support/coinbaseadvanced.py +17 -0
- ccxt/async_support/{coinbasepro.py → coinbaseexchange.py} +233 -99
- ccxt/async_support/coinbaseinternational.py +428 -88
- ccxt/async_support/coincatch.py +5152 -0
- ccxt/async_support/coincheck.py +121 -38
- ccxt/async_support/coinex.py +4020 -3339
- ccxt/async_support/coinlist.py +273 -116
- ccxt/async_support/coinmate.py +204 -97
- ccxt/async_support/coinmetro.py +203 -110
- ccxt/async_support/coinone.py +142 -68
- ccxt/async_support/coinsph.py +206 -89
- ccxt/async_support/coinspot.py +137 -62
- ccxt/async_support/cryptocom.py +515 -185
- ccxt/async_support/currencycom.py +203 -85
- ccxt/async_support/defx.py +2066 -0
- ccxt/async_support/delta.py +404 -109
- ccxt/async_support/deribit.py +557 -323
- ccxt/async_support/digifinex.py +340 -223
- ccxt/async_support/ellipx.py +1826 -0
- ccxt/async_support/exmo.py +259 -128
- ccxt/async_support/gate.py +1472 -463
- ccxt/async_support/gemini.py +206 -84
- ccxt/async_support/hashkey.py +4164 -0
- ccxt/async_support/hitbtc.py +334 -178
- ccxt/async_support/hollaex.py +134 -83
- ccxt/async_support/htx.py +1095 -563
- ccxt/async_support/huobijp.py +105 -56
- ccxt/async_support/hyperliquid.py +1633 -268
- ccxt/async_support/idex.py +148 -95
- ccxt/async_support/independentreserve.py +236 -31
- ccxt/async_support/indodax.py +165 -62
- ccxt/async_support/kraken.py +871 -354
- ccxt/async_support/krakenfutures.py +324 -100
- ccxt/async_support/kucoin.py +917 -357
- ccxt/async_support/kucoinfutures.py +1004 -149
- ccxt/async_support/kuna.py +138 -106
- ccxt/async_support/latoken.py +135 -79
- ccxt/async_support/lbank.py +290 -113
- ccxt/async_support/luno.py +112 -62
- ccxt/async_support/lykke.py +104 -55
- ccxt/async_support/mercado.py +36 -29
- ccxt/async_support/mexc.py +995 -429
- ccxt/async_support/myokx.py +43 -0
- ccxt/async_support/ndax.py +163 -82
- ccxt/async_support/novadax.py +121 -75
- ccxt/async_support/oceanex.py +175 -59
- ccxt/async_support/okcoin.py +222 -163
- ccxt/async_support/okx.py +1776 -454
- ccxt/async_support/onetrading.py +132 -414
- ccxt/async_support/oxfun.py +2832 -0
- ccxt/async_support/p2b.py +79 -51
- ccxt/async_support/paradex.py +2017 -0
- ccxt/async_support/paymium.py +56 -32
- ccxt/async_support/phemex.py +572 -196
- ccxt/async_support/poloniex.py +218 -95
- ccxt/async_support/poloniexfutures.py +260 -92
- ccxt/async_support/probit.py +143 -110
- ccxt/async_support/timex.py +123 -70
- ccxt/async_support/tokocrypto.py +129 -93
- ccxt/async_support/tradeogre.py +39 -25
- ccxt/async_support/upbit.py +322 -113
- ccxt/async_support/vertex.py +2983 -0
- ccxt/async_support/wavesexchange.py +227 -173
- ccxt/async_support/wazirx.py +145 -65
- ccxt/async_support/whitebit.py +533 -138
- ccxt/async_support/woo.py +1137 -296
- ccxt/async_support/woofipro.py +2716 -0
- ccxt/async_support/xt.py +4628 -0
- ccxt/async_support/yobit.py +160 -92
- ccxt/async_support/zaif.py +80 -33
- ccxt/async_support/zonda.py +140 -69
- ccxt/base/errors.py +51 -20
- ccxt/base/exchange.py +1722 -480
- ccxt/base/precise.py +10 -0
- ccxt/base/types.py +223 -4
- ccxt/bequant.py +1 -1
- ccxt/bigone.py +329 -202
- ccxt/binance.py +3030 -1087
- ccxt/binancecoinm.py +2 -1
- ccxt/binanceus.py +12 -1
- ccxt/binanceusdm.py +3 -1
- ccxt/bingx.py +3104 -880
- ccxt/bit2c.py +119 -38
- ccxt/bitbank.py +215 -76
- ccxt/bitbns.py +124 -53
- ccxt/bitfinex.py +3235 -1078
- ccxt/bitfinex1.py +1710 -0
- ccxt/bitflyer.py +238 -49
- ccxt/bitget.py +1513 -563
- ccxt/bithumb.py +198 -65
- ccxt/bitmart.py +1320 -435
- ccxt/bitmex.py +308 -111
- ccxt/bitopro.py +256 -96
- ccxt/bitrue.py +365 -233
- ccxt/bitso.py +201 -89
- ccxt/bitstamp.py +438 -269
- ccxt/bitteam.py +179 -73
- ccxt/bitvavo.py +180 -70
- ccxt/bl3p.py +92 -25
- ccxt/blockchaincom.py +193 -79
- ccxt/blofin.py +392 -148
- ccxt/btcalpha.py +161 -55
- ccxt/btcbox.py +250 -34
- ccxt/btcmarkets.py +232 -85
- ccxt/btcturk.py +159 -60
- ccxt/bybit.py +2231 -1193
- ccxt/cex.py +1408 -1329
- ccxt/coinbase.py +1454 -287
- ccxt/coinbaseadvanced.py +17 -0
- ccxt/{coinbasepro.py → coinbaseexchange.py} +233 -99
- ccxt/coinbaseinternational.py +428 -88
- ccxt/coincatch.py +5152 -0
- ccxt/coincheck.py +121 -38
- ccxt/coinex.py +4020 -3339
- ccxt/coinlist.py +273 -116
- ccxt/coinmate.py +204 -97
- ccxt/coinmetro.py +203 -110
- ccxt/coinone.py +142 -68
- ccxt/coinsph.py +206 -89
- ccxt/coinspot.py +137 -62
- ccxt/cryptocom.py +515 -185
- ccxt/currencycom.py +203 -85
- ccxt/defx.py +2065 -0
- ccxt/delta.py +404 -109
- ccxt/deribit.py +557 -323
- ccxt/digifinex.py +340 -223
- ccxt/ellipx.py +1826 -0
- ccxt/exmo.py +259 -128
- ccxt/gate.py +1472 -463
- ccxt/gemini.py +206 -84
- ccxt/hashkey.py +4164 -0
- ccxt/hitbtc.py +334 -178
- ccxt/hollaex.py +134 -83
- ccxt/htx.py +1095 -563
- ccxt/huobijp.py +105 -56
- ccxt/hyperliquid.py +1632 -268
- ccxt/idex.py +148 -95
- ccxt/independentreserve.py +235 -31
- ccxt/indodax.py +165 -62
- ccxt/kraken.py +871 -354
- ccxt/krakenfutures.py +324 -100
- ccxt/kucoin.py +917 -357
- ccxt/kucoinfutures.py +1004 -149
- ccxt/kuna.py +138 -106
- ccxt/latoken.py +135 -79
- ccxt/lbank.py +290 -113
- ccxt/luno.py +112 -62
- ccxt/lykke.py +104 -55
- ccxt/mercado.py +36 -29
- ccxt/mexc.py +994 -429
- ccxt/myokx.py +43 -0
- ccxt/ndax.py +163 -82
- ccxt/novadax.py +121 -75
- ccxt/oceanex.py +175 -59
- ccxt/okcoin.py +222 -163
- ccxt/okx.py +1776 -454
- ccxt/onetrading.py +132 -414
- ccxt/oxfun.py +2831 -0
- ccxt/p2b.py +79 -51
- ccxt/paradex.py +2017 -0
- ccxt/paymium.py +56 -32
- ccxt/phemex.py +572 -196
- ccxt/poloniex.py +218 -95
- ccxt/poloniexfutures.py +260 -92
- ccxt/pro/__init__.py +29 -5
- ccxt/pro/alpaca.py +32 -17
- ccxt/pro/ascendex.py +62 -14
- ccxt/pro/bequant.py +4 -0
- ccxt/pro/binance.py +1596 -329
- ccxt/pro/binancecoinm.py +1 -0
- ccxt/pro/binanceus.py +2 -9
- ccxt/pro/binanceusdm.py +2 -0
- ccxt/pro/bingx.py +527 -134
- ccxt/pro/bitcoincom.py +4 -1
- ccxt/pro/bitfinex.py +731 -266
- ccxt/pro/bitfinex1.py +635 -0
- ccxt/pro/bitget.py +726 -357
- ccxt/pro/bithumb.py +380 -0
- ccxt/pro/bitmart.py +138 -39
- ccxt/pro/bitmex.py +199 -40
- ccxt/pro/bitopro.py +25 -13
- ccxt/pro/bitrue.py +31 -32
- ccxt/pro/bitstamp.py +7 -6
- ccxt/pro/bitvavo.py +203 -81
- ccxt/pro/blockchaincom.py +30 -17
- ccxt/pro/blofin.py +692 -0
- ccxt/pro/bybit.py +791 -82
- ccxt/pro/cex.py +99 -51
- ccxt/pro/coinbase.py +220 -30
- ccxt/{async_support/hitbtc3.py → pro/coinbaseadvanced.py} +5 -5
- ccxt/pro/{coinbasepro.py → coinbaseexchange.py} +19 -19
- ccxt/pro/coinbaseinternational.py +193 -30
- ccxt/pro/coincatch.py +1464 -0
- ccxt/pro/coincheck.py +11 -6
- ccxt/pro/coinex.py +965 -665
- ccxt/pro/coinone.py +17 -10
- ccxt/pro/cryptocom.py +446 -66
- ccxt/pro/currencycom.py +11 -10
- ccxt/pro/defx.py +832 -0
- ccxt/pro/deribit.py +167 -31
- ccxt/pro/exmo.py +252 -20
- ccxt/pro/gate.py +729 -64
- ccxt/pro/gemini.py +44 -26
- ccxt/pro/hashkey.py +802 -0
- ccxt/pro/hitbtc.py +208 -103
- ccxt/pro/hollaex.py +25 -9
- ccxt/pro/htx.py +83 -39
- ccxt/pro/huobijp.py +17 -16
- ccxt/pro/hyperliquid.py +502 -31
- ccxt/pro/idex.py +28 -13
- ccxt/pro/independentreserve.py +21 -16
- ccxt/pro/kraken.py +298 -51
- ccxt/pro/krakenfutures.py +166 -75
- ccxt/pro/kucoin.py +395 -77
- ccxt/pro/kucoinfutures.py +400 -99
- ccxt/pro/lbank.py +52 -31
- ccxt/pro/luno.py +12 -10
- ccxt/pro/mexc.py +400 -50
- ccxt/pro/myokx.py +28 -0
- ccxt/pro/ndax.py +25 -12
- ccxt/pro/okcoin.py +28 -9
- ccxt/pro/okx.py +935 -124
- ccxt/pro/onetrading.py +41 -24
- ccxt/pro/oxfun.py +1054 -0
- ccxt/pro/p2b.py +100 -24
- ccxt/pro/paradex.py +352 -0
- ccxt/pro/phemex.py +92 -33
- ccxt/pro/poloniex.py +128 -49
- ccxt/pro/poloniexfutures.py +53 -32
- ccxt/pro/probit.py +92 -85
- ccxt/pro/upbit.py +401 -8
- ccxt/pro/vertex.py +943 -0
- ccxt/pro/wazirx.py +46 -28
- ccxt/pro/whitebit.py +65 -12
- ccxt/pro/woo.py +437 -65
- ccxt/pro/woofipro.py +1271 -0
- ccxt/pro/xt.py +1067 -0
- ccxt/probit.py +143 -110
- ccxt/static_dependencies/__init__.py +1 -1
- ccxt/static_dependencies/lark/__init__.py +38 -0
- ccxt/static_dependencies/lark/__pyinstaller/__init__.py +6 -0
- ccxt/static_dependencies/lark/__pyinstaller/hook-lark.py +14 -0
- ccxt/static_dependencies/lark/ast_utils.py +59 -0
- ccxt/static_dependencies/lark/common.py +86 -0
- ccxt/static_dependencies/lark/exceptions.py +292 -0
- ccxt/static_dependencies/lark/grammar.py +130 -0
- ccxt/static_dependencies/lark/grammars/__init__.py +0 -0
- ccxt/static_dependencies/lark/indenter.py +143 -0
- ccxt/static_dependencies/lark/lark.py +658 -0
- ccxt/static_dependencies/lark/lexer.py +678 -0
- ccxt/static_dependencies/lark/load_grammar.py +1428 -0
- ccxt/static_dependencies/lark/parse_tree_builder.py +391 -0
- ccxt/static_dependencies/lark/parser_frontends.py +257 -0
- ccxt/static_dependencies/lark/parsers/__init__.py +0 -0
- ccxt/static_dependencies/lark/parsers/cyk.py +340 -0
- ccxt/static_dependencies/lark/parsers/earley.py +314 -0
- ccxt/static_dependencies/lark/parsers/earley_common.py +42 -0
- ccxt/static_dependencies/lark/parsers/earley_forest.py +801 -0
- ccxt/static_dependencies/lark/parsers/grammar_analysis.py +203 -0
- ccxt/static_dependencies/lark/parsers/lalr_analysis.py +332 -0
- ccxt/static_dependencies/lark/parsers/lalr_interactive_parser.py +158 -0
- ccxt/static_dependencies/lark/parsers/lalr_parser.py +122 -0
- ccxt/static_dependencies/lark/parsers/lalr_parser_state.py +110 -0
- ccxt/static_dependencies/lark/parsers/xearley.py +165 -0
- ccxt/static_dependencies/lark/py.typed +0 -0
- ccxt/static_dependencies/lark/reconstruct.py +107 -0
- ccxt/static_dependencies/lark/tools/__init__.py +70 -0
- ccxt/static_dependencies/lark/tools/nearley.py +202 -0
- ccxt/static_dependencies/lark/tools/serialize.py +32 -0
- ccxt/static_dependencies/lark/tools/standalone.py +196 -0
- ccxt/static_dependencies/lark/tree.py +267 -0
- ccxt/static_dependencies/lark/tree_matcher.py +186 -0
- ccxt/static_dependencies/lark/tree_templates.py +180 -0
- ccxt/static_dependencies/lark/utils.py +343 -0
- ccxt/static_dependencies/lark/visitors.py +596 -0
- ccxt/static_dependencies/marshmallow/__init__.py +81 -0
- ccxt/static_dependencies/marshmallow/base.py +65 -0
- ccxt/static_dependencies/marshmallow/class_registry.py +94 -0
- ccxt/static_dependencies/marshmallow/decorators.py +231 -0
- ccxt/static_dependencies/marshmallow/error_store.py +60 -0
- ccxt/static_dependencies/marshmallow/exceptions.py +71 -0
- ccxt/static_dependencies/marshmallow/fields.py +2114 -0
- ccxt/static_dependencies/marshmallow/orderedset.py +89 -0
- ccxt/static_dependencies/marshmallow/py.typed +0 -0
- ccxt/static_dependencies/marshmallow/schema.py +1228 -0
- ccxt/static_dependencies/marshmallow/types.py +12 -0
- ccxt/static_dependencies/marshmallow/utils.py +378 -0
- ccxt/static_dependencies/marshmallow/validate.py +678 -0
- ccxt/static_dependencies/marshmallow/warnings.py +2 -0
- ccxt/static_dependencies/marshmallow_dataclass/__init__.py +1047 -0
- ccxt/static_dependencies/marshmallow_dataclass/collection_field.py +51 -0
- ccxt/static_dependencies/marshmallow_dataclass/lazy_class_attribute.py +45 -0
- ccxt/static_dependencies/marshmallow_dataclass/mypy.py +71 -0
- ccxt/static_dependencies/marshmallow_dataclass/py.typed +0 -0
- ccxt/static_dependencies/marshmallow_dataclass/typing.py +14 -0
- ccxt/static_dependencies/marshmallow_dataclass/union_field.py +82 -0
- ccxt/static_dependencies/marshmallow_oneofschema/__init__.py +1 -0
- ccxt/static_dependencies/marshmallow_oneofschema/one_of_schema.py +193 -0
- ccxt/static_dependencies/marshmallow_oneofschema/py.typed +0 -0
- ccxt/static_dependencies/starknet/__init__.py +0 -0
- ccxt/static_dependencies/starknet/cairo/__init__.py +0 -0
- ccxt/static_dependencies/starknet/cairo/data_types.py +123 -0
- ccxt/static_dependencies/starknet/cairo/deprecated_parse/__init__.py +0 -0
- ccxt/static_dependencies/starknet/cairo/deprecated_parse/cairo_types.py +77 -0
- ccxt/static_dependencies/starknet/cairo/deprecated_parse/parser.py +46 -0
- ccxt/static_dependencies/starknet/cairo/deprecated_parse/parser_transformer.py +138 -0
- ccxt/static_dependencies/starknet/cairo/felt.py +64 -0
- ccxt/static_dependencies/starknet/cairo/type_parser.py +121 -0
- ccxt/static_dependencies/starknet/cairo/v1/__init__.py +0 -0
- ccxt/static_dependencies/starknet/cairo/v1/type_parser.py +59 -0
- ccxt/static_dependencies/starknet/cairo/v2/__init__.py +0 -0
- ccxt/static_dependencies/starknet/cairo/v2/type_parser.py +77 -0
- ccxt/static_dependencies/starknet/ccxt_utils.py +7 -0
- ccxt/static_dependencies/starknet/common.py +15 -0
- ccxt/static_dependencies/starknet/constants.py +39 -0
- ccxt/static_dependencies/starknet/hash/__init__.py +0 -0
- ccxt/static_dependencies/starknet/hash/address.py +79 -0
- ccxt/static_dependencies/starknet/hash/compiled_class_hash_objects.py +111 -0
- ccxt/static_dependencies/starknet/hash/selector.py +16 -0
- ccxt/static_dependencies/starknet/hash/storage.py +12 -0
- ccxt/static_dependencies/starknet/hash/utils.py +78 -0
- ccxt/static_dependencies/starknet/models/__init__.py +0 -0
- ccxt/static_dependencies/starknet/models/typed_data.py +45 -0
- ccxt/static_dependencies/starknet/serialization/__init__.py +24 -0
- ccxt/static_dependencies/starknet/serialization/_calldata_reader.py +40 -0
- ccxt/static_dependencies/starknet/serialization/_context.py +142 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/__init__.py +10 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/_common.py +82 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/array_serializer.py +43 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/bool_serializer.py +37 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/byte_array_serializer.py +66 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/cairo_data_serializer.py +71 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/enum_serializer.py +71 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/felt_serializer.py +50 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/named_tuple_serializer.py +58 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/option_serializer.py +43 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/output_serializer.py +40 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/payload_serializer.py +72 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/struct_serializer.py +36 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/tuple_serializer.py +36 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/uint256_serializer.py +76 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/uint_serializer.py +100 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/unit_serializer.py +32 -0
- ccxt/static_dependencies/starknet/serialization/errors.py +10 -0
- ccxt/static_dependencies/starknet/serialization/factory.py +229 -0
- ccxt/static_dependencies/starknet/serialization/function_serialization_adapter.py +110 -0
- ccxt/static_dependencies/starknet/serialization/tuple_dataclass.py +59 -0
- ccxt/static_dependencies/starknet/utils/__init__.py +0 -0
- ccxt/static_dependencies/starknet/utils/constructor_args_translator.py +86 -0
- ccxt/static_dependencies/starknet/utils/iterable.py +13 -0
- ccxt/static_dependencies/starknet/utils/schema.py +13 -0
- ccxt/static_dependencies/starknet/utils/typed_data.py +182 -0
- ccxt/static_dependencies/starkware/__init__.py +0 -0
- ccxt/static_dependencies/starkware/crypto/__init__.py +0 -0
- ccxt/static_dependencies/starkware/crypto/fast_pedersen_hash.py +50 -0
- ccxt/static_dependencies/starkware/crypto/math_utils.py +78 -0
- ccxt/static_dependencies/starkware/crypto/signature.py +2344 -0
- ccxt/static_dependencies/starkware/crypto/utils.py +63 -0
- ccxt/static_dependencies/sympy/__init__.py +0 -0
- ccxt/static_dependencies/sympy/core/__init__.py +0 -0
- ccxt/static_dependencies/sympy/core/intfunc.py +35 -0
- ccxt/static_dependencies/sympy/external/__init__.py +0 -0
- ccxt/static_dependencies/sympy/external/gmpy.py +345 -0
- ccxt/static_dependencies/sympy/external/importtools.py +187 -0
- ccxt/static_dependencies/sympy/external/ntheory.py +637 -0
- ccxt/static_dependencies/sympy/external/pythonmpq.py +341 -0
- ccxt/static_dependencies/typing_inspect/__init__.py +0 -0
- ccxt/static_dependencies/typing_inspect/typing_inspect.py +851 -0
- ccxt/test/{test_async.py → tests_async.py} +456 -391
- ccxt/test/tests_helpers.py +285 -0
- ccxt/test/tests_init.py +39 -0
- ccxt/test/{test_sync.py → tests_sync.py} +456 -393
- ccxt/timex.py +123 -70
- ccxt/tokocrypto.py +129 -93
- ccxt/tradeogre.py +39 -25
- ccxt/upbit.py +322 -113
- ccxt/vertex.py +2983 -0
- ccxt/wavesexchange.py +227 -173
- ccxt/wazirx.py +145 -65
- ccxt/whitebit.py +533 -138
- ccxt/woo.py +1137 -296
- ccxt/woofipro.py +2716 -0
- ccxt/xt.py +4627 -0
- ccxt/yobit.py +159 -92
- ccxt/zaif.py +80 -33
- ccxt/zonda.py +140 -69
- ccxt-4.4.48.dist-info/LICENSE.txt +21 -0
- ccxt-4.4.48.dist-info/METADATA +646 -0
- ccxt-4.4.48.dist-info/RECORD +669 -0
- {ccxt-4.2.77.dist-info → ccxt-4.4.48.dist-info}/WHEEL +1 -1
- ccxt/abstract/bitbay.py +0 -47
- ccxt/abstract/bitfinex2.py +0 -139
- ccxt/abstract/hitbtc3.py +0 -115
- ccxt/async_support/bitbay.py +0 -17
- ccxt/async_support/bitfinex2.py +0 -3496
- ccxt/async_support/flowbtc.py +0 -34
- ccxt/bitbay.py +0 -17
- ccxt/bitfinex2.py +0 -3496
- ccxt/flowbtc.py +0 -34
- ccxt/hitbtc3.py +0 -16
- ccxt/pro/bitfinex2.py +0 -1081
- ccxt/test/base/__init__.py +0 -28
- ccxt/test/base/test_account.py +0 -26
- ccxt/test/base/test_balance.py +0 -56
- ccxt/test/base/test_borrow_interest.py +0 -35
- ccxt/test/base/test_borrow_rate.py +0 -32
- ccxt/test/base/test_calculate_fee.py +0 -51
- ccxt/test/base/test_crypto.py +0 -127
- ccxt/test/base/test_currency.py +0 -76
- ccxt/test/base/test_datetime.py +0 -103
- ccxt/test/base/test_decimal_to_precision.py +0 -392
- ccxt/test/base/test_deep_extend.py +0 -68
- ccxt/test/base/test_deposit_withdrawal.py +0 -50
- ccxt/test/base/test_exchange_datetime_functions.py +0 -76
- ccxt/test/base/test_funding_rate_history.py +0 -29
- ccxt/test/base/test_last_price.py +0 -32
- ccxt/test/base/test_ledger_entry.py +0 -45
- ccxt/test/base/test_ledger_item.py +0 -48
- ccxt/test/base/test_leverage_tier.py +0 -33
- ccxt/test/base/test_margin_mode.py +0 -24
- ccxt/test/base/test_margin_modification.py +0 -35
- ccxt/test/base/test_market.py +0 -190
- ccxt/test/base/test_number.py +0 -411
- ccxt/test/base/test_ohlcv.py +0 -32
- ccxt/test/base/test_open_interest.py +0 -32
- ccxt/test/base/test_order.py +0 -64
- ccxt/test/base/test_order_book.py +0 -63
- ccxt/test/base/test_position.py +0 -60
- ccxt/test/base/test_shared_methods.py +0 -345
- ccxt/test/base/test_status.py +0 -24
- ccxt/test/base/test_throttle.py +0 -126
- ccxt/test/base/test_ticker.py +0 -86
- ccxt/test/base/test_trade.py +0 -47
- ccxt/test/base/test_trading_fee.py +0 -26
- ccxt/test/base/test_transaction.py +0 -39
- ccxt-4.2.77.dist-info/METADATA +0 -626
- ccxt-4.2.77.dist-info/RECORD +0 -534
- {ccxt-4.2.77.dist-info → ccxt-4.4.48.dist-info}/top_level.txt +0 -0
ccxt/pro/oxfun.py
ADDED
@@ -0,0 +1,1054 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
# PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
|
4
|
+
# https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
|
5
|
+
|
6
|
+
import ccxt.async_support
|
7
|
+
from ccxt.async_support.base.ws.cache import ArrayCache, ArrayCacheBySymbolById, ArrayCacheBySymbolBySide, ArrayCacheByTimestamp
|
8
|
+
import hashlib
|
9
|
+
from ccxt.base.types import Balances, Int, Market, Num, Order, OrderBook, OrderSide, OrderType, Position, Str, Strings, Ticker, Tickers, Trade
|
10
|
+
from ccxt.async_support.base.ws.client import Client
|
11
|
+
from typing import List
|
12
|
+
from ccxt.base.errors import AuthenticationError
|
13
|
+
from ccxt.base.errors import ArgumentsRequired
|
14
|
+
from ccxt.base.errors import BadRequest
|
15
|
+
|
16
|
+
|
17
|
+
class oxfun(ccxt.async_support.oxfun):
|
18
|
+
|
19
|
+
def describe(self):
|
20
|
+
return self.deep_extend(super(oxfun, self).describe(), {
|
21
|
+
'has': {
|
22
|
+
'ws': True,
|
23
|
+
'watchTrades': True,
|
24
|
+
'watchTradesForSymbols': True,
|
25
|
+
'watchOrderBook': True,
|
26
|
+
'watchOrderBookForSymbols': True,
|
27
|
+
'watchOHLCV': True,
|
28
|
+
'watchOHLCVForSymbols': True,
|
29
|
+
'watchOrders': True,
|
30
|
+
'watchMyTrades': False,
|
31
|
+
'watchTicker': True,
|
32
|
+
'watchTickers': True,
|
33
|
+
'watchBidsAsks': True,
|
34
|
+
'watchBalance': True,
|
35
|
+
'createOrderWs': True,
|
36
|
+
'editOrderWs': True,
|
37
|
+
'cancelOrderWs': True,
|
38
|
+
'cancelOrdersWs': True,
|
39
|
+
},
|
40
|
+
'urls': {
|
41
|
+
'api': {
|
42
|
+
'ws': 'wss://api.ox.fun/v2/websocket',
|
43
|
+
'test': 'wss://stgapi.ox.fun/v2/websocket',
|
44
|
+
},
|
45
|
+
},
|
46
|
+
'options': {
|
47
|
+
'timeframes': {
|
48
|
+
'1m': '60s',
|
49
|
+
'3m': '180s',
|
50
|
+
'5m': '300s',
|
51
|
+
'15m': '900s',
|
52
|
+
'30m': '1800s',
|
53
|
+
'1h': '3600s',
|
54
|
+
'2h': '7200s',
|
55
|
+
'4h': '14400s',
|
56
|
+
'6h': '21600s',
|
57
|
+
'12h': '43200s',
|
58
|
+
'1d': '86400s',
|
59
|
+
},
|
60
|
+
'watchOrderBook': {
|
61
|
+
'channel': 'depth', # depth, depthL5, depthL10, depthL25
|
62
|
+
},
|
63
|
+
},
|
64
|
+
'streaming': {
|
65
|
+
'ping': self.ping,
|
66
|
+
'keepAlive': 50000,
|
67
|
+
},
|
68
|
+
})
|
69
|
+
|
70
|
+
async def subscribe_multiple(self, messageHashes, argsArray, params={}):
|
71
|
+
url = self.urls['api']['ws']
|
72
|
+
request: dict = {
|
73
|
+
'op': 'subscribe',
|
74
|
+
'args': argsArray,
|
75
|
+
}
|
76
|
+
return await self.watch_multiple(url, messageHashes, self.extend(request, params), messageHashes)
|
77
|
+
|
78
|
+
async def watch_trades(self, symbol: str, since: Int = None, limit: Int = None, params={}) -> List[Trade]:
|
79
|
+
"""
|
80
|
+
watches information on multiple trades made in a market
|
81
|
+
|
82
|
+
https://docs.ox.fun/?json#trade
|
83
|
+
|
84
|
+
:param str symbol: unified market symbol of the market trades were made in
|
85
|
+
:param int [since]: the earliest time in ms to fetch orders for
|
86
|
+
:param int [limit]: the maximum number of trade structures to retrieve
|
87
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
88
|
+
:param int|str [params.tag]: If given it will be echoed in the reply and the max size of tag is 32
|
89
|
+
:returns dict[]: a list of `trade structures <https://docs.ccxt.com/#/?id=trade-structure>`
|
90
|
+
"""
|
91
|
+
return await self.watch_trades_for_symbols([symbol], since, limit, params)
|
92
|
+
|
93
|
+
async def watch_trades_for_symbols(self, symbols: List[str], since: Int = None, limit: Int = None, params={}) -> List[Trade]:
|
94
|
+
"""
|
95
|
+
get the list of most recent trades for a particular symbol
|
96
|
+
|
97
|
+
https://docs.ox.fun/?json#trade
|
98
|
+
|
99
|
+
:param str[] symbols:
|
100
|
+
:param int [since]: timestamp in ms of the earliest trade to fetch
|
101
|
+
:param int [limit]: the maximum amount of trades to fetch
|
102
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
103
|
+
:param int|str [params.tag]: If given it will be echoed in the reply and the max size of tag is 32
|
104
|
+
:returns dict[]: a list of `trade structures <https://docs.ccxt.com/#/?id=public-trades>`
|
105
|
+
"""
|
106
|
+
await self.load_markets()
|
107
|
+
symbols = self.market_symbols(symbols, None, False)
|
108
|
+
args = []
|
109
|
+
messageHashes = []
|
110
|
+
for i in range(0, len(symbols)):
|
111
|
+
symbol = symbols[i]
|
112
|
+
messageHash = 'trades' + ':' + symbol
|
113
|
+
messageHashes.append(messageHash)
|
114
|
+
marketId = self.market_id(symbol)
|
115
|
+
arg = 'trade:' + marketId
|
116
|
+
args.append(arg)
|
117
|
+
trades = await self.subscribe_multiple(messageHashes, args, params)
|
118
|
+
if self.newUpdates:
|
119
|
+
first = self.safe_dict(trades, 0, {})
|
120
|
+
tradeSymbol = self.safe_string(first, 'symbol')
|
121
|
+
limit = trades.getLimit(tradeSymbol, limit)
|
122
|
+
return self.filter_by_since_limit(trades, since, limit, 'timestamp', True)
|
123
|
+
|
124
|
+
def handle_trades(self, client: Client, message):
|
125
|
+
#
|
126
|
+
# {
|
127
|
+
# table: 'trade',
|
128
|
+
# data: [
|
129
|
+
# {
|
130
|
+
# side: 'SELL',
|
131
|
+
# quantity: '0.074',
|
132
|
+
# matchType: 'TAKER',
|
133
|
+
# price: '3079.5',
|
134
|
+
# marketCode: 'ETH-USD-SWAP-LIN',
|
135
|
+
# tradeId: '400017157974517783',
|
136
|
+
# timestamp: '1716124156643'
|
137
|
+
# }
|
138
|
+
# ]
|
139
|
+
# }
|
140
|
+
#
|
141
|
+
data = self.safe_list(message, 'data', [])
|
142
|
+
for i in range(0, len(data)):
|
143
|
+
trade = self.safe_dict(data, i, {})
|
144
|
+
parsedTrade = self.parse_ws_trade(trade)
|
145
|
+
symbol = self.safe_string(parsedTrade, 'symbol')
|
146
|
+
messageHash = 'trades:' + symbol
|
147
|
+
if not (symbol in self.trades):
|
148
|
+
tradesLimit = self.safe_integer(self.options, 'tradesLimit', 1000)
|
149
|
+
self.trades[symbol] = ArrayCache(tradesLimit)
|
150
|
+
stored = self.trades[symbol]
|
151
|
+
stored.append(parsedTrade)
|
152
|
+
client.resolve(stored, messageHash)
|
153
|
+
|
154
|
+
def parse_ws_trade(self, trade, market=None) -> Trade:
|
155
|
+
#
|
156
|
+
# {
|
157
|
+
# side: 'SELL',
|
158
|
+
# quantity: '0.074',
|
159
|
+
# matchType: 'TAKER',
|
160
|
+
# price: '3079.5',
|
161
|
+
# marketCode: 'ETH-USD-SWAP-LIN',
|
162
|
+
# tradeId: '400017157974517783',
|
163
|
+
# timestamp: '1716124156643'
|
164
|
+
# }
|
165
|
+
#
|
166
|
+
marketId = self.safe_string(trade, 'marketCode')
|
167
|
+
market = self.safe_market(marketId, market)
|
168
|
+
timestamp = self.safe_integer(trade, 'timestamp')
|
169
|
+
return self.safe_trade({
|
170
|
+
'info': trade,
|
171
|
+
'timestamp': timestamp,
|
172
|
+
'datetime': self.iso8601(timestamp),
|
173
|
+
'symbol': market['symbol'],
|
174
|
+
'id': self.safe_string(trade, 'tradeId'),
|
175
|
+
'order': None,
|
176
|
+
'type': None,
|
177
|
+
'takerOrMaker': self.safe_string_lower(trade, 'matchType'),
|
178
|
+
'side': self.safe_string_lower(trade, 'side'),
|
179
|
+
'price': self.safe_number(trade, 'price'),
|
180
|
+
'amount': self.safe_number(trade, 'quantity'),
|
181
|
+
'cost': None,
|
182
|
+
'fee': None,
|
183
|
+
})
|
184
|
+
|
185
|
+
async def watch_ohlcv(self, symbol: str, timeframe='1m', since: Int = None, limit: Int = None, params={}) -> List[list]:
|
186
|
+
"""
|
187
|
+
watches historical candlestick data containing the open, high, low, and close price, and the volume of a market
|
188
|
+
|
189
|
+
https://docs.ox.fun/?json#candles
|
190
|
+
|
191
|
+
:param str symbol: unified symbol of the market to fetch OHLCV data for
|
192
|
+
:param str timeframe: the length of time each candle represents
|
193
|
+
:param int [since]: timestamp in ms of the earliest candle to fetch
|
194
|
+
:param int [limit]: the maximum amount of candles to fetch
|
195
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
196
|
+
:param int|str [params.tag]: If given it will be echoed in the reply and the max size of tag is 32
|
197
|
+
:returns int[][]: A list of candles ordered, open, high, low, close, volume
|
198
|
+
"""
|
199
|
+
await self.load_markets()
|
200
|
+
market = self.market(symbol)
|
201
|
+
timeframes = self.safe_dict(self.options, 'timeframes', {})
|
202
|
+
interval = self.safe_string(timeframes, timeframe, timeframe)
|
203
|
+
args = 'candles' + interval + ':' + market['id']
|
204
|
+
messageHash = 'ohlcv:' + symbol + ':' + timeframe
|
205
|
+
url = self.urls['api']['ws']
|
206
|
+
request: dict = {
|
207
|
+
'op': 'subscribe',
|
208
|
+
'args': [args],
|
209
|
+
}
|
210
|
+
ohlcvs = await self.watch(url, messageHash, self.extend(request, params), messageHash)
|
211
|
+
if self.newUpdates:
|
212
|
+
limit = ohlcvs.getLimit(symbol, limit)
|
213
|
+
return self.filter_by_since_limit(ohlcvs, since, limit, 0, True)
|
214
|
+
|
215
|
+
async def watch_ohlcv_for_symbols(self, symbolsAndTimeframes: List[List[str]], since: Int = None, limit: Int = None, params={}):
|
216
|
+
"""
|
217
|
+
watches historical candlestick data containing the open, high, low, and close price, and the volume of a market
|
218
|
+
|
219
|
+
https://docs.ox.fun/?json#candles
|
220
|
+
|
221
|
+
:param str[][] symbolsAndTimeframes: array of arrays containing unified symbols and timeframes to fetch OHLCV data for, example [['BTC/USDT', '1m'], ['LTC/USDT', '5m']]
|
222
|
+
:param int [since]: timestamp in ms of the earliest candle to fetch
|
223
|
+
:param int [limit]: the maximum amount of candles to fetch
|
224
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
225
|
+
:param int|str [params.tag]: If given it will be echoed in the reply and the max size of tag is 32
|
226
|
+
:returns int[][]: A list of candles ordered, open, high, low, close, volume
|
227
|
+
"""
|
228
|
+
symbolsLength = len(symbolsAndTimeframes)
|
229
|
+
if symbolsLength == 0 or not isinstance(symbolsAndTimeframes[0], list):
|
230
|
+
raise ArgumentsRequired(self.id + " watchOHLCVForSymbols() requires a an array of symbols and timeframes, like [['BTC/USDT:OX', '1m'], ['OX/USDT', '5m']]")
|
231
|
+
await self.load_markets()
|
232
|
+
args = []
|
233
|
+
messageHashes = []
|
234
|
+
timeframes = self.safe_dict(self.options, 'timeframes', {})
|
235
|
+
for i in range(0, len(symbolsAndTimeframes)):
|
236
|
+
symbolAndTimeframe = symbolsAndTimeframes[i]
|
237
|
+
sym = symbolAndTimeframe[0]
|
238
|
+
tf = symbolAndTimeframe[1]
|
239
|
+
marketId = self.market_id(sym)
|
240
|
+
interval = self.safe_string(timeframes, tf, tf)
|
241
|
+
arg = 'candles' + interval + ':' + marketId
|
242
|
+
args.append(arg)
|
243
|
+
messageHash = 'multi:ohlcv:' + sym + ':' + tf
|
244
|
+
messageHashes.append(messageHash)
|
245
|
+
symbol, timeframe, candles = await self.subscribe_multiple(messageHashes, args, params)
|
246
|
+
if self.newUpdates:
|
247
|
+
limit = candles.getLimit(symbol, limit)
|
248
|
+
filtered = self.filter_by_since_limit(candles, since, limit, 0, True)
|
249
|
+
return self.create_ohlcv_object(symbol, timeframe, filtered)
|
250
|
+
|
251
|
+
def handle_ohlcv(self, client: Client, message):
|
252
|
+
#
|
253
|
+
# {
|
254
|
+
# "table": "candles60s",
|
255
|
+
# "data": [
|
256
|
+
# {
|
257
|
+
# "marketCode": "BTC-USD-SWAP-LIN",
|
258
|
+
# "candle": [
|
259
|
+
# "1594313762698", #timestamp
|
260
|
+
# "9633.1", #open
|
261
|
+
# "9693.9", #high
|
262
|
+
# "9238.1", #low
|
263
|
+
# "9630.2", #close
|
264
|
+
# "45247", #volume in OX
|
265
|
+
# "5.3" #volume in Contracts
|
266
|
+
# ]
|
267
|
+
# }
|
268
|
+
# ]
|
269
|
+
# }
|
270
|
+
#
|
271
|
+
table = self.safe_string(message, 'table')
|
272
|
+
parts = table.split('candles')
|
273
|
+
timeframeId = self.safe_string(parts, 1, '')
|
274
|
+
timeframe = self.find_timeframe(timeframeId)
|
275
|
+
messageData = self.safe_list(message, 'data', [])
|
276
|
+
data = self.safe_dict(messageData, 0, {})
|
277
|
+
marketId = self.safe_string(data, 'marketCode')
|
278
|
+
market = self.safe_market(marketId)
|
279
|
+
symbol = self.safe_symbol(marketId, market)
|
280
|
+
if not (symbol in self.ohlcvs):
|
281
|
+
self.ohlcvs[symbol] = {}
|
282
|
+
if not (timeframe in self.ohlcvs[symbol]):
|
283
|
+
limit = self.safe_integer(self.options, 'OHLCVLimit', 1000)
|
284
|
+
self.ohlcvs[symbol][timeframe] = ArrayCacheByTimestamp(limit)
|
285
|
+
candle = self.safe_list(data, 'candle', [])
|
286
|
+
parsed = self.parse_ws_ohlcv(candle, market)
|
287
|
+
stored = self.ohlcvs[symbol][timeframe]
|
288
|
+
stored.append(parsed)
|
289
|
+
messageHash = 'ohlcv:' + symbol + ':' + timeframe
|
290
|
+
client.resolve(stored, messageHash)
|
291
|
+
# for multiOHLCV we need special object, to other "multi"
|
292
|
+
# methods, because OHLCV response item does not contain symbol
|
293
|
+
# or timeframe, thus otherwise it would be unrecognizable
|
294
|
+
messageHashForMulti = 'multi:' + messageHash
|
295
|
+
client.resolve([symbol, timeframe, stored], messageHashForMulti)
|
296
|
+
|
297
|
+
def parse_ws_ohlcv(self, ohlcv, market: Market = None) -> list:
|
298
|
+
#
|
299
|
+
# [
|
300
|
+
# "1594313762698", #timestamp
|
301
|
+
# "9633.1", #open
|
302
|
+
# "9693.9", #high
|
303
|
+
# "9238.1", #low
|
304
|
+
# "9630.2", #close
|
305
|
+
# "45247", #volume in OX
|
306
|
+
# "5.3" #volume in Contracts
|
307
|
+
# ]
|
308
|
+
#
|
309
|
+
return [
|
310
|
+
self.safe_integer(ohlcv, 0),
|
311
|
+
self.safe_number(ohlcv, 1),
|
312
|
+
self.safe_number(ohlcv, 2),
|
313
|
+
self.safe_number(ohlcv, 3),
|
314
|
+
self.safe_number(ohlcv, 4),
|
315
|
+
self.safe_number(ohlcv, 6),
|
316
|
+
]
|
317
|
+
|
318
|
+
async def watch_order_book(self, symbol: str, limit: Int = None, params={}) -> OrderBook:
|
319
|
+
"""
|
320
|
+
watches information on open orders with bid(buy) and ask(sell) prices, volumes and other data
|
321
|
+
|
322
|
+
https://docs.ox.fun/?json#fixed-size-order-book
|
323
|
+
https://docs.ox.fun/?json#full-order-book
|
324
|
+
|
325
|
+
:param str symbol: unified symbol of the market to fetch the order book for
|
326
|
+
:param int [limit]: the maximum amount of order book entries to return
|
327
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
328
|
+
:returns dict: A dictionary of `order book structures <https://docs.ccxt.com/#/?id=order-book-structure>` indexed by market symbols
|
329
|
+
"""
|
330
|
+
return await self.watch_order_book_for_symbols([symbol], limit, params)
|
331
|
+
|
332
|
+
async def watch_order_book_for_symbols(self, symbols: List[str], limit: Int = None, params={}) -> OrderBook:
|
333
|
+
"""
|
334
|
+
watches information on open orders with bid(buy) and ask(sell) prices, volumes and other data
|
335
|
+
|
336
|
+
https://docs.ox.fun/?json#fixed-size-order-book
|
337
|
+
https://docs.ox.fun/?json#full-order-book
|
338
|
+
|
339
|
+
:param str[] symbols: unified array of symbols
|
340
|
+
:param int [limit]: the maximum amount of order book entries to return
|
341
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
342
|
+
:param int|str [params.tag]: If given it will be echoed in the reply and the max size of tag is 32
|
343
|
+
:returns dict: A dictionary of `order book structures <https://docs.ccxt.com/#/?id=order-book-structure>` indexed by market symbols
|
344
|
+
"""
|
345
|
+
await self.load_markets()
|
346
|
+
symbols = self.market_symbols(symbols)
|
347
|
+
channel = 'depth'
|
348
|
+
options = self.safe_dict(self.options, 'watchOrderBook', {})
|
349
|
+
defaultChannel = self.safe_string(options, 'channel')
|
350
|
+
if defaultChannel is not None:
|
351
|
+
channel = defaultChannel
|
352
|
+
elif limit is not None:
|
353
|
+
if limit <= 5:
|
354
|
+
channel = 'depthL5'
|
355
|
+
elif limit <= 10:
|
356
|
+
channel = 'depthL10'
|
357
|
+
elif limit <= 25:
|
358
|
+
channel = 'depthL25'
|
359
|
+
args = []
|
360
|
+
messageHashes = []
|
361
|
+
for i in range(0, len(symbols)):
|
362
|
+
symbol = symbols[i]
|
363
|
+
messageHash = 'orderbook:' + symbol
|
364
|
+
messageHashes.append(messageHash)
|
365
|
+
marketId = self.market_id(symbol)
|
366
|
+
arg = channel + ':' + marketId
|
367
|
+
args.append(arg)
|
368
|
+
orderbook = await self.subscribe_multiple(messageHashes, args, params)
|
369
|
+
return orderbook.limit()
|
370
|
+
|
371
|
+
def handle_order_book(self, client: Client, message):
|
372
|
+
#
|
373
|
+
# {
|
374
|
+
# "table": "depth",
|
375
|
+
# "data": {
|
376
|
+
# "seqNum": "100170478917895032",
|
377
|
+
# "asks": [
|
378
|
+
# [0.01, 100500],
|
379
|
+
# ...
|
380
|
+
# ],
|
381
|
+
# "bids": [
|
382
|
+
# [69.69696, 69],
|
383
|
+
# ...
|
384
|
+
# ],
|
385
|
+
# "checksum": 261021645,
|
386
|
+
# "marketCode": "OX-USDT",
|
387
|
+
# "timestamp": 1716204786184
|
388
|
+
# },
|
389
|
+
# "action": "partial"
|
390
|
+
# }
|
391
|
+
#
|
392
|
+
data = self.safe_dict(message, 'data', {})
|
393
|
+
marketId = self.safe_string(data, 'marketCode')
|
394
|
+
symbol = self.safe_symbol(marketId)
|
395
|
+
timestamp = self.safe_integer(data, 'timestamp')
|
396
|
+
messageHash = 'orderbook:' + symbol
|
397
|
+
if not (symbol in self.orderbooks):
|
398
|
+
self.orderbooks[symbol] = self.order_book({})
|
399
|
+
orderbook = self.orderbooks[symbol]
|
400
|
+
snapshot = self.parse_order_book(data, symbol, timestamp, 'asks', 'bids')
|
401
|
+
orderbook.reset(snapshot)
|
402
|
+
orderbook['nonce'] = self.safe_integer(data, 'seqNum')
|
403
|
+
self.orderbooks[symbol] = orderbook
|
404
|
+
client.resolve(orderbook, messageHash)
|
405
|
+
|
406
|
+
async def watch_ticker(self, symbol: str, params={}) -> Ticker:
|
407
|
+
"""
|
408
|
+
|
409
|
+
https://docs.ox.fun/?json#ticker
|
410
|
+
|
411
|
+
watches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
|
412
|
+
:param str symbol: unified symbol of the market to fetch the ticker for
|
413
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
414
|
+
:param int|str [params.tag]: If given it will be echoed in the reply and the max size of tag is 32
|
415
|
+
:returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
|
416
|
+
"""
|
417
|
+
ticker = await self.watch_tickers([symbol], params)
|
418
|
+
return self.safe_value(ticker, symbol)
|
419
|
+
|
420
|
+
async def watch_tickers(self, symbols: Strings = None, params={}) -> Tickers:
|
421
|
+
"""
|
422
|
+
|
423
|
+
https://docs.ox.fun/?json#ticker
|
424
|
+
|
425
|
+
watches a price ticker, a statistical calculation with the information calculated over the past 24 hours for all markets of a specific list
|
426
|
+
:param str[] [symbols]: unified symbol of the market to fetch the ticker for
|
427
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
428
|
+
:param int|str [params.tag]: If given it will be echoed in the reply and the max size of tag is 32
|
429
|
+
:returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
|
430
|
+
"""
|
431
|
+
await self.load_markets()
|
432
|
+
allSymbols = (symbols is None)
|
433
|
+
sym = symbols
|
434
|
+
args = []
|
435
|
+
if allSymbols:
|
436
|
+
sym = self.symbols
|
437
|
+
args.append('ticker:all')
|
438
|
+
messageHashes = []
|
439
|
+
for i in range(0, len(sym)):
|
440
|
+
symbol = sym[i]
|
441
|
+
messageHash = 'tickers' + ':' + symbol
|
442
|
+
messageHashes.append(messageHash)
|
443
|
+
marketId = self.market_id(symbol)
|
444
|
+
if not allSymbols:
|
445
|
+
args.append('ticker:' + marketId)
|
446
|
+
newTicker = await self.subscribe_multiple(messageHashes, args, params)
|
447
|
+
if self.newUpdates:
|
448
|
+
result = {}
|
449
|
+
result[newTicker['symbol']] = newTicker
|
450
|
+
return result
|
451
|
+
return self.filter_by_array(self.tickers, 'symbol', symbols)
|
452
|
+
|
453
|
+
def handle_ticker(self, client: Client, message):
|
454
|
+
#
|
455
|
+
# {
|
456
|
+
# "table": "ticker",
|
457
|
+
# "data": [
|
458
|
+
# {
|
459
|
+
# "last": "3088.6",
|
460
|
+
# "open24h": "3087.2",
|
461
|
+
# "high24h": "3142.0",
|
462
|
+
# "low24h": "3053.9",
|
463
|
+
# "volume24h": "450512672.1800",
|
464
|
+
# "currencyVolume24h": "1458.579",
|
465
|
+
# "openInterest": "3786.801",
|
466
|
+
# "marketCode": "ETH-USD-SWAP-LIN",
|
467
|
+
# "timestamp": "1716212747050",
|
468
|
+
# "lastQty": "0.813",
|
469
|
+
# "markPrice": "3088.6",
|
470
|
+
# "lastMarkPrice": "3088.6",
|
471
|
+
# "indexPrice": "3086.5"
|
472
|
+
# },
|
473
|
+
# ...
|
474
|
+
# ]
|
475
|
+
# }
|
476
|
+
#
|
477
|
+
data = self.safe_list(message, 'data', [])
|
478
|
+
for i in range(0, len(data)):
|
479
|
+
rawTicker = self.safe_dict(data, i, {})
|
480
|
+
ticker = self.parse_ticker(rawTicker)
|
481
|
+
symbol = ticker['symbol']
|
482
|
+
messageHash = 'tickers:' + symbol
|
483
|
+
self.tickers[symbol] = ticker
|
484
|
+
client.resolve(ticker, messageHash)
|
485
|
+
|
486
|
+
async def watch_bids_asks(self, symbols: Strings = None, params={}) -> Tickers:
|
487
|
+
"""
|
488
|
+
|
489
|
+
https://docs.ox.fun/?json#best-bid-ask
|
490
|
+
|
491
|
+
watches best bid & ask for symbols
|
492
|
+
:param str[] symbols: unified symbol of the market to fetch the ticker for
|
493
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
494
|
+
:returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
|
495
|
+
"""
|
496
|
+
await self.load_markets()
|
497
|
+
symbols = self.market_symbols(symbols, None, False)
|
498
|
+
messageHashes = []
|
499
|
+
args = []
|
500
|
+
for i in range(0, len(symbols)):
|
501
|
+
market = self.market(symbols[i])
|
502
|
+
args.append('bestBidAsk:' + market['id'])
|
503
|
+
messageHashes.append('bidask:' + market['symbol'])
|
504
|
+
newTickers = await self.subscribe_multiple(messageHashes, args, params)
|
505
|
+
if self.newUpdates:
|
506
|
+
tickers: dict = {}
|
507
|
+
tickers[newTickers['symbol']] = newTickers
|
508
|
+
return tickers
|
509
|
+
return self.filter_by_array(self.bidsasks, 'symbol', symbols)
|
510
|
+
|
511
|
+
def handle_bid_ask(self, client: Client, message):
|
512
|
+
#
|
513
|
+
# {
|
514
|
+
# "table": "bestBidAsk",
|
515
|
+
# "data": {
|
516
|
+
# "ask": [
|
517
|
+
# 19045.0,
|
518
|
+
# 1.0
|
519
|
+
# ],
|
520
|
+
# "checksum": 3790706311,
|
521
|
+
# "marketCode": "BTC-USD-SWAP-LIN",
|
522
|
+
# "bid": [
|
523
|
+
# 19015.0,
|
524
|
+
# 1.0
|
525
|
+
# ],
|
526
|
+
# "timestamp": "1665456882928"
|
527
|
+
# }
|
528
|
+
# }
|
529
|
+
#
|
530
|
+
data = self.safe_dict(message, 'data', {})
|
531
|
+
parsedTicker = self.parse_ws_bid_ask(data)
|
532
|
+
symbol = parsedTicker['symbol']
|
533
|
+
self.bidsasks[symbol] = parsedTicker
|
534
|
+
messageHash = 'bidask:' + symbol
|
535
|
+
client.resolve(parsedTicker, messageHash)
|
536
|
+
|
537
|
+
def parse_ws_bid_ask(self, ticker, market=None):
|
538
|
+
marketId = self.safe_string(ticker, 'marketCode')
|
539
|
+
market = self.safe_market(marketId, market)
|
540
|
+
symbol = self.safe_string(market, 'symbol')
|
541
|
+
timestamp = self.safe_integer(ticker, 'timestamp')
|
542
|
+
ask = self.safe_list(ticker, 'ask', [])
|
543
|
+
bid = self.safe_list(ticker, 'bid', [])
|
544
|
+
return self.safe_ticker({
|
545
|
+
'symbol': symbol,
|
546
|
+
'timestamp': timestamp,
|
547
|
+
'datetime': self.iso8601(timestamp),
|
548
|
+
'ask': self.safe_number(ask, 0),
|
549
|
+
'askVolume': self.safe_number(ask, 1),
|
550
|
+
'bid': self.safe_number(bid, 0),
|
551
|
+
'bidVolume': self.safe_number(bid, 1),
|
552
|
+
'info': ticker,
|
553
|
+
}, market)
|
554
|
+
|
555
|
+
async def watch_balance(self, params={}) -> Balances:
|
556
|
+
"""
|
557
|
+
|
558
|
+
https://docs.ox.fun/?json#balance-channel
|
559
|
+
|
560
|
+
watch balance and get the amount of funds available for trading or funds locked in orders
|
561
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
562
|
+
:param int|str [params.tag]: If given it will be echoed in the reply and the max size of tag is 32
|
563
|
+
:returns dict: a `balance structure <https://docs.ccxt.com/#/?id=balance-structure>`
|
564
|
+
"""
|
565
|
+
await self.load_markets()
|
566
|
+
self.authenticate()
|
567
|
+
args = 'balance:all'
|
568
|
+
messageHash = 'balance'
|
569
|
+
url = self.urls['api']['ws']
|
570
|
+
request: dict = {
|
571
|
+
'op': 'subscribe',
|
572
|
+
'args': [args],
|
573
|
+
}
|
574
|
+
return await self.watch(url, messageHash, self.extend(request, params), messageHash)
|
575
|
+
|
576
|
+
def handle_balance(self, client, message):
|
577
|
+
#
|
578
|
+
# {
|
579
|
+
# "table": "balance",
|
580
|
+
# "accountId": "106464",
|
581
|
+
# "timestamp": "1716549132780",
|
582
|
+
# "tradeType": "PORTFOLIO",
|
583
|
+
# "data": [
|
584
|
+
# {
|
585
|
+
# "instrumentId": "xOX",
|
586
|
+
# "total": "23.375591220",
|
587
|
+
# "available": "23.375591220",
|
588
|
+
# "reserved": "0",
|
589
|
+
# "quantityLastUpdated": "1716509744262",
|
590
|
+
# "locked": "0"
|
591
|
+
# },
|
592
|
+
# ...
|
593
|
+
# ]
|
594
|
+
# }
|
595
|
+
#
|
596
|
+
balances = self.safe_list(message, 'data')
|
597
|
+
timestamp = self.safe_integer(message, 'timestamp')
|
598
|
+
self.balance['info'] = message
|
599
|
+
self.balance['timestamp'] = timestamp
|
600
|
+
self.balance['datetime'] = self.iso8601(timestamp)
|
601
|
+
for i in range(0, len(balances)):
|
602
|
+
balance = self.safe_dict(balances, i, {})
|
603
|
+
currencyId = self.safe_string(balance, 'instrumentId')
|
604
|
+
code = self.safe_currency_code(currencyId)
|
605
|
+
if not (code in self.balance):
|
606
|
+
self.balance[code] = self.account()
|
607
|
+
account = self.balance[code]
|
608
|
+
account['total'] = self.safe_string(balance, 'total')
|
609
|
+
account['used'] = self.safe_string(balance, 'reserved')
|
610
|
+
account['free'] = self.safe_string(balance, 'available')
|
611
|
+
self.balance[code] = account
|
612
|
+
self.balance = self.safe_balance(self.balance)
|
613
|
+
client.resolve(self.balance, 'balance')
|
614
|
+
|
615
|
+
async def watch_positions(self, symbols: Strings = None, since: Int = None, limit: Int = None, params={}) -> List[Position]:
|
616
|
+
"""
|
617
|
+
|
618
|
+
https://docs.ox.fun/?json#position-channel
|
619
|
+
|
620
|
+
watch all open positions
|
621
|
+
:param str[]|None symbols: list of unified market symbols
|
622
|
+
@param since
|
623
|
+
@param limit
|
624
|
+
:param dict params: extra parameters specific to the exchange API endpoint
|
625
|
+
:param int|str [params.tag]: If given it will be echoed in the reply and the max size of tag is 32
|
626
|
+
:returns dict[]: a list of `position structure <https://docs.ccxt.com/en/latest/manual.html#position-structure>`
|
627
|
+
"""
|
628
|
+
await self.load_markets()
|
629
|
+
await self.authenticate()
|
630
|
+
allSymbols = (symbols is None)
|
631
|
+
sym = symbols
|
632
|
+
args = []
|
633
|
+
if allSymbols:
|
634
|
+
sym = self.symbols
|
635
|
+
args.append('position:all')
|
636
|
+
messageHashes = []
|
637
|
+
for i in range(0, len(sym)):
|
638
|
+
symbol = sym[i]
|
639
|
+
messageHash = 'positions' + ':' + symbol
|
640
|
+
messageHashes.append(messageHash)
|
641
|
+
marketId = self.market_id(symbol)
|
642
|
+
if not allSymbols:
|
643
|
+
args.append('position:' + marketId)
|
644
|
+
newPositions = await self.subscribe_multiple(messageHashes, args, params)
|
645
|
+
if self.newUpdates:
|
646
|
+
return newPositions
|
647
|
+
return self.filter_by_symbols_since_limit(self.positions, symbols, since, limit, True)
|
648
|
+
|
649
|
+
def handle_positions(self, client: Client, message):
|
650
|
+
#
|
651
|
+
# {
|
652
|
+
# "table": "position",
|
653
|
+
# "accountId": "106464",
|
654
|
+
# "timestamp": "1716550771582",
|
655
|
+
# "data": [
|
656
|
+
# {
|
657
|
+
# "instrumentId": "ETH-USD-SWAP-LIN",
|
658
|
+
# "quantity": "0.01",
|
659
|
+
# "lastUpdated": "1716550757299",
|
660
|
+
# "contractValCurrency": "ETH",
|
661
|
+
# "entryPrice": "3709.6",
|
662
|
+
# "positionPnl": "-5.000",
|
663
|
+
# "estLiquidationPrice": "743.4",
|
664
|
+
# "margin": "0",
|
665
|
+
# "leverage": "0"
|
666
|
+
# }
|
667
|
+
# ]
|
668
|
+
# }
|
669
|
+
#
|
670
|
+
if self.positions is None:
|
671
|
+
self.positions = ArrayCacheBySymbolBySide()
|
672
|
+
cache = self.positions
|
673
|
+
data = self.safe_list(message, 'data', [])
|
674
|
+
for i in range(0, len(data)):
|
675
|
+
rawPosition = self.safe_dict(data, i, {})
|
676
|
+
position = self.parse_ws_position(rawPosition)
|
677
|
+
symbol = position['symbol']
|
678
|
+
messageHash = 'positions:' + symbol
|
679
|
+
cache.append(position)
|
680
|
+
client.resolve(position, messageHash)
|
681
|
+
|
682
|
+
def parse_ws_position(self, position, market: Market = None):
|
683
|
+
#
|
684
|
+
# {
|
685
|
+
# "instrumentId": "ETH-USD-SWAP-LIN",
|
686
|
+
# "quantity": "0.01",
|
687
|
+
# "lastUpdated": "1716550757299",
|
688
|
+
# "contractValCurrency": "ETH",
|
689
|
+
# "entryPrice": "3709.6",
|
690
|
+
# "positionPnl": "-5.000",
|
691
|
+
# "estLiquidationPrice": "743.4",
|
692
|
+
# "margin": "0", # Currently always reports 0
|
693
|
+
# "leverage": "0" # Currently always reports 0
|
694
|
+
# }
|
695
|
+
#
|
696
|
+
marketId = self.safe_string(position, 'instrumentId')
|
697
|
+
market = self.safe_market(marketId, market)
|
698
|
+
return self.safe_position({
|
699
|
+
'info': position,
|
700
|
+
'id': None,
|
701
|
+
'symbol': market['symbol'],
|
702
|
+
'notional': None,
|
703
|
+
'marginMode': 'cross',
|
704
|
+
'liquidationPrice': self.safe_number(position, 'estLiquidationPrice'),
|
705
|
+
'entryPrice': self.safe_number(position, 'entryPrice'),
|
706
|
+
'unrealizedPnl': self.safe_number(position, 'positionPnl'),
|
707
|
+
'realizedPnl': None,
|
708
|
+
'percentage': None,
|
709
|
+
'contracts': self.safe_number(position, 'quantity'),
|
710
|
+
'contractSize': None,
|
711
|
+
'markPrice': None,
|
712
|
+
'lastPrice': None,
|
713
|
+
'side': None,
|
714
|
+
'hedged': None,
|
715
|
+
'timestamp': None,
|
716
|
+
'datetime': None,
|
717
|
+
'lastUpdateTimestamp': self.safe_integer(position, 'lastUpdated'),
|
718
|
+
'maintenanceMargin': None,
|
719
|
+
'maintenanceMarginPercentage': None,
|
720
|
+
'collateral': None,
|
721
|
+
'initialMargin': None,
|
722
|
+
'initialMarginPercentage': None,
|
723
|
+
'leverage': None,
|
724
|
+
'marginRatio': None,
|
725
|
+
'stopLossPrice': None,
|
726
|
+
'takeProfitPrice': None,
|
727
|
+
})
|
728
|
+
|
729
|
+
async def watch_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
|
730
|
+
"""
|
731
|
+
watches information on multiple orders made by the user
|
732
|
+
|
733
|
+
https://docs.ox.fun/?json#order-channel
|
734
|
+
|
735
|
+
:param str symbol: unified market symbol of the market orders were made in
|
736
|
+
:param int [since]: the earliest time in ms to fetch orders for
|
737
|
+
:param int [limit]: the maximum number of order structures to retrieve
|
738
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
739
|
+
:param int|str [params.tag]: If given it will be echoed in the reply and the max size of tag is 32
|
740
|
+
:returns dict[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
|
741
|
+
"""
|
742
|
+
await self.load_markets()
|
743
|
+
await self.authenticate()
|
744
|
+
messageHash = 'orders'
|
745
|
+
args = 'order:'
|
746
|
+
market = self.safe_market(symbol)
|
747
|
+
if symbol is None:
|
748
|
+
args += 'all'
|
749
|
+
else:
|
750
|
+
messageHash += ':' + symbol
|
751
|
+
args += ':' + market['id']
|
752
|
+
request: dict = {
|
753
|
+
'op': 'subscribe',
|
754
|
+
'args': [
|
755
|
+
args,
|
756
|
+
],
|
757
|
+
}
|
758
|
+
url = self.urls['api']['ws']
|
759
|
+
orders = await self.watch(url, messageHash, request, messageHash)
|
760
|
+
if self.newUpdates:
|
761
|
+
limit = orders.getLimit(symbol, limit)
|
762
|
+
return self.filter_by_symbol_since_limit(orders, symbol, since, limit, True)
|
763
|
+
|
764
|
+
def handle_orders(self, client: Client, message):
|
765
|
+
#
|
766
|
+
# {
|
767
|
+
# "table": "order",
|
768
|
+
# "data": [
|
769
|
+
# {
|
770
|
+
# "accountId": "106464",
|
771
|
+
# "clientOrderId": "1716713676233",
|
772
|
+
# "orderId": "1000116921319",
|
773
|
+
# "price": "1000.0",
|
774
|
+
# "quantity": "0.01",
|
775
|
+
# "amount": "0.0",
|
776
|
+
# "side": "BUY",
|
777
|
+
# "status": "OPEN",
|
778
|
+
# "marketCode": "ETH-USD-SWAP-LIN",
|
779
|
+
# "timeInForce": "MAKER_ONLY",
|
780
|
+
# "timestamp": "1716713677834",
|
781
|
+
# "remainQuantity": "0.01",
|
782
|
+
# "limitPrice": "1000.0",
|
783
|
+
# "notice": "OrderOpened",
|
784
|
+
# "orderType": "LIMIT",
|
785
|
+
# "isTriggered": "false",
|
786
|
+
# "displayQuantity": "0.01"
|
787
|
+
# }
|
788
|
+
# ]
|
789
|
+
# }
|
790
|
+
#
|
791
|
+
data = self.safe_list(message, 'data', [])
|
792
|
+
messageHash = 'orders'
|
793
|
+
if self.orders is None:
|
794
|
+
limit = self.safe_integer(self.options, 'ordersLimit', 1000)
|
795
|
+
self.orders = ArrayCacheBySymbolById(limit)
|
796
|
+
orders = self.orders
|
797
|
+
for i in range(0, len(data)):
|
798
|
+
order = self.safe_dict(data, i, {})
|
799
|
+
parsedOrder = self.parse_order(order)
|
800
|
+
orders.append(parsedOrder)
|
801
|
+
messageHash += ':' + parsedOrder['symbol']
|
802
|
+
client.resolve(self.orders, messageHash)
|
803
|
+
|
804
|
+
async def create_order_ws(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, params={}) -> Order:
|
805
|
+
"""
|
806
|
+
|
807
|
+
https://docs.ox.fun/?json#order-commands
|
808
|
+
|
809
|
+
create a trade order
|
810
|
+
:param str symbol: unified symbol of the market to create an order in
|
811
|
+
:param str type: 'market', 'limit', 'STOP_LIMIT' or 'STOP_MARKET'
|
812
|
+
:param str side: 'buy' or 'sell'
|
813
|
+
:param float amount: how much of currency you want to trade in units of base currency
|
814
|
+
:param float [price]: the price at which the order is to be fulfilled, in units of the quote currency, ignored in market orders
|
815
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
816
|
+
:param int [params.clientOrderId]: a unique id for the order
|
817
|
+
:param int [params.timestamp]: in milliseconds. If an order reaches the matching engine and the current timestamp exceeds timestamp + recvWindow, then the order will be rejected.
|
818
|
+
:param int [params.recvWindow]: in milliseconds. If an order reaches the matching engine and the current timestamp exceeds timestamp + recvWindow, then the order will be rejected. If timestamp is provided without recvWindow, then a default recvWindow of 1000ms is used.
|
819
|
+
:param float [params.cost]: the quote quantity that can be used alternative for the amount for market buy orders
|
820
|
+
:param float [params.triggerPrice]: The price at which a trigger order is triggered at
|
821
|
+
:param float [params.limitPrice]: Limit price for the STOP_LIMIT order
|
822
|
+
:param bool [params.postOnly]: if True, the order will only be posted if it will be a maker order
|
823
|
+
:param str [params.timeInForce]: GTC(default), IOC, FOK, PO, MAKER_ONLY or MAKER_ONLY_REPRICE(reprices order to the best maker only price if the specified price were to lead to a taker trade)
|
824
|
+
:param str [params.selfTradePreventionMode]: NONE, EXPIRE_MAKER, EXPIRE_TAKER or EXPIRE_BOTH for more info check here {@link https://docs.ox.fun/?json#self-trade-prevention-modes}
|
825
|
+
:param str [params.displayQuantity]: for an iceberg order, pass both quantity and displayQuantity fields in the order request
|
826
|
+
:returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
|
827
|
+
"""
|
828
|
+
await self.load_markets()
|
829
|
+
await self.authenticate()
|
830
|
+
messageHash = str(self.nonce())
|
831
|
+
request: dict = {
|
832
|
+
'op': 'placeorder',
|
833
|
+
'tag': messageHash,
|
834
|
+
}
|
835
|
+
params = self.omit(params, 'tag')
|
836
|
+
orderRequest: dict = self.create_order_request(symbol, type, side, amount, price, params)
|
837
|
+
timestamp = self.safe_integer(orderRequest, 'timestamp')
|
838
|
+
if timestamp is None:
|
839
|
+
orderRequest['timestamp'] = self.milliseconds()
|
840
|
+
request['data'] = orderRequest
|
841
|
+
url = self.urls['api']['ws']
|
842
|
+
return await self.watch(url, messageHash, request, messageHash)
|
843
|
+
|
844
|
+
async def edit_order_ws(self, id: str, symbol: str, type: OrderType, side: OrderSide, amount: Num = None, price: Num = None, params={}) -> Order:
|
845
|
+
"""
|
846
|
+
edit a trade order
|
847
|
+
|
848
|
+
https://docs.ox.fun/?json#modify-order
|
849
|
+
|
850
|
+
:param str id: order id
|
851
|
+
:param str symbol: unified symbol of the market to create an order in
|
852
|
+
:param str type: 'market' or 'limit'
|
853
|
+
:param str side: 'buy' or 'sell'
|
854
|
+
:param float amount: how much of the currency you want to trade in units of the base currency
|
855
|
+
:param float|None [price]: the price at which the order is to be fulfilled, in units of the quote currency, ignored in market orders
|
856
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
857
|
+
:param int [params.timestamp]: in milliseconds. If an order reaches the matching engine and the current timestamp exceeds timestamp + recvWindow, then the order will be rejected.
|
858
|
+
:param int [params.recvWindow]: in milliseconds. If an order reaches the matching engine and the current timestamp exceeds timestamp + recvWindow, then the order will be rejected. If timestamp is provided without recvWindow, then a default recvWindow of 1000ms is used.
|
859
|
+
:returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
|
860
|
+
"""
|
861
|
+
await self.load_markets()
|
862
|
+
await self.authenticate()
|
863
|
+
messageHash = str(self.nonce())
|
864
|
+
request: dict = {
|
865
|
+
'op': 'modifyorder',
|
866
|
+
'tag': messageHash,
|
867
|
+
}
|
868
|
+
params = self.omit(params, 'tag')
|
869
|
+
orderRequest: dict = self.create_order_request(symbol, type, side, amount, price, params)
|
870
|
+
orderRequest = self.extend(orderRequest, {'orderId': id})
|
871
|
+
timestamp = self.safe_integer(orderRequest, 'timestamp')
|
872
|
+
if timestamp is None:
|
873
|
+
orderRequest['timestamp'] = self.milliseconds()
|
874
|
+
request['data'] = orderRequest
|
875
|
+
url = self.urls['api']['ws']
|
876
|
+
return await self.watch(url, messageHash, request, messageHash)
|
877
|
+
|
878
|
+
def handle_place_orders(self, client: Client, message):
|
879
|
+
#
|
880
|
+
# {
|
881
|
+
# "event": "placeorder",
|
882
|
+
# "submitted": True,
|
883
|
+
# "tag": "1716934577",
|
884
|
+
# "timestamp": "1716932973899",
|
885
|
+
# "data": {
|
886
|
+
# "marketCode": "ETH-USD-SWAP-LIN",
|
887
|
+
# "side": "BUY",
|
888
|
+
# "orderType": "LIMIT",
|
889
|
+
# "quantity": "0.010",
|
890
|
+
# "timeInForce": "GTC",
|
891
|
+
# "price": "400.0",
|
892
|
+
# "limitPrice": "400.0",
|
893
|
+
# "orderId": "1000117429736",
|
894
|
+
# "source": 13
|
895
|
+
# }
|
896
|
+
# }
|
897
|
+
#
|
898
|
+
#
|
899
|
+
# Failure response format
|
900
|
+
# {
|
901
|
+
# "event": "placeorder",
|
902
|
+
# "submitted": False,
|
903
|
+
# "message": "JSON data format is invalid",
|
904
|
+
# "code": "20009",
|
905
|
+
# "timestamp": "1716932877381"
|
906
|
+
# }
|
907
|
+
#
|
908
|
+
messageHash = self.safe_string(message, 'tag')
|
909
|
+
submitted = self.safe_bool(message, 'submitted')
|
910
|
+
# filter out partial errors
|
911
|
+
if not submitted:
|
912
|
+
method = self.safe_string(message, 'event')
|
913
|
+
stringMsg = self.json(message)
|
914
|
+
code = self.safe_integer(message, 'code')
|
915
|
+
self.handle_errors(code, None, client.url, method, None, stringMsg, message, None, None)
|
916
|
+
data = self.safe_value(message, 'data', {})
|
917
|
+
order = self.parse_order(data)
|
918
|
+
client.resolve(order, messageHash)
|
919
|
+
|
920
|
+
async def cancel_order_ws(self, id: str, symbol: Str = None, params={}) -> Order:
|
921
|
+
"""
|
922
|
+
|
923
|
+
https://docs.ox.fun/?json#cancel-order
|
924
|
+
|
925
|
+
cancels an open order
|
926
|
+
:param str id: order id
|
927
|
+
:param str symbol: unified market symbol, default is None
|
928
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
929
|
+
:returns dict: an list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
|
930
|
+
"""
|
931
|
+
if symbol is None:
|
932
|
+
raise ArgumentsRequired(self.id + ' cancelOrderWs() requires a symbol argument')
|
933
|
+
await self.load_markets()
|
934
|
+
await self.authenticate()
|
935
|
+
messageHash = str(self.nonce())
|
936
|
+
data: dict = {
|
937
|
+
'marketCode': self.market_id(symbol),
|
938
|
+
'orderId': id,
|
939
|
+
}
|
940
|
+
request: dict = {
|
941
|
+
'op': 'cancelorder',
|
942
|
+
'tag': messageHash,
|
943
|
+
'data': data,
|
944
|
+
}
|
945
|
+
url = self.urls['api']['ws']
|
946
|
+
return await self.watch(url, messageHash, request, messageHash)
|
947
|
+
|
948
|
+
async def cancel_orders_ws(self, ids: List[str], symbol: Str = None, params={}):
|
949
|
+
"""
|
950
|
+
|
951
|
+
https://www.okx.com/docs-v5/en/#order-book-trading-trade-ws-mass-cancel-order
|
952
|
+
|
953
|
+
cancel multiple orders
|
954
|
+
:param str[] ids: order ids
|
955
|
+
:param str symbol: unified market symbol, default is None
|
956
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
957
|
+
:returns dict: an list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
|
958
|
+
"""
|
959
|
+
idsLength: number = len(ids)
|
960
|
+
if idsLength > 20:
|
961
|
+
raise BadRequest(self.id + ' cancelOrdersWs() accepts up to 20 ids at a time')
|
962
|
+
if symbol is None:
|
963
|
+
raise ArgumentsRequired(self.id + ' cancelOrdersWs() requires a symbol argument')
|
964
|
+
await self.load_markets()
|
965
|
+
await self.authenticate()
|
966
|
+
messageHash = str(self.nonce())
|
967
|
+
marketId = self.market_id(symbol)
|
968
|
+
dataArray = []
|
969
|
+
for i in range(0, idsLength):
|
970
|
+
data: dict = {
|
971
|
+
'instId': marketId,
|
972
|
+
'ordId': ids[i],
|
973
|
+
}
|
974
|
+
dataArray.append(data)
|
975
|
+
request: dict = {
|
976
|
+
'op': 'cancelorders',
|
977
|
+
'tag': messageHash,
|
978
|
+
'dataArray': dataArray,
|
979
|
+
}
|
980
|
+
url = self.urls['api']['ws']
|
981
|
+
return await self.watch(url, messageHash, self.deep_extend(request, params), messageHash)
|
982
|
+
|
983
|
+
async def authenticate(self, params={}):
|
984
|
+
url = self.urls['api']['ws']
|
985
|
+
client = self.client(url)
|
986
|
+
messageHash = 'authenticated'
|
987
|
+
future = client.future(messageHash)
|
988
|
+
authenticated = self.safe_dict(client.subscriptions, messageHash)
|
989
|
+
if authenticated is None:
|
990
|
+
self.check_required_credentials()
|
991
|
+
timestamp = self.milliseconds()
|
992
|
+
payload = str(timestamp) + 'GET/auth/self/verify'
|
993
|
+
signature = self.hmac(self.encode(payload), self.encode(self.secret), hashlib.sha256, 'base64')
|
994
|
+
request: dict = {
|
995
|
+
'op': 'login',
|
996
|
+
'data': {
|
997
|
+
'apiKey': self.apiKey,
|
998
|
+
'timestamp': timestamp,
|
999
|
+
'signature': signature,
|
1000
|
+
},
|
1001
|
+
}
|
1002
|
+
message = self.extend(request, params)
|
1003
|
+
self.watch(url, messageHash, message, messageHash)
|
1004
|
+
return await future
|
1005
|
+
|
1006
|
+
def handle_authentication_message(self, client: Client, message):
|
1007
|
+
authenticated = self.safe_bool(message, 'success', False)
|
1008
|
+
messageHash = 'authenticated'
|
1009
|
+
if authenticated:
|
1010
|
+
# we resolve the future here permanently so authentication only happens once
|
1011
|
+
future = self.safe_dict(client.futures, messageHash)
|
1012
|
+
future.resolve(True)
|
1013
|
+
else:
|
1014
|
+
error = AuthenticationError(self.json(message))
|
1015
|
+
client.reject(error, messageHash)
|
1016
|
+
if messageHash in client.subscriptions:
|
1017
|
+
del client.subscriptions[messageHash]
|
1018
|
+
|
1019
|
+
def ping(self, client: Client):
|
1020
|
+
return 'ping'
|
1021
|
+
|
1022
|
+
def handle_pong(self, client: Client, message):
|
1023
|
+
client.lastPong = self.milliseconds()
|
1024
|
+
return message
|
1025
|
+
|
1026
|
+
def handle_message(self, client: Client, message):
|
1027
|
+
if message == 'pong':
|
1028
|
+
self.handle_pong(client, message)
|
1029
|
+
return
|
1030
|
+
table = self.safe_string(message, 'table')
|
1031
|
+
data = self.safe_list(message, 'data', [])
|
1032
|
+
event = self.safe_string(message, 'event')
|
1033
|
+
if (table is not None) and (data is not None):
|
1034
|
+
if table == 'trade':
|
1035
|
+
self.handle_trades(client, message)
|
1036
|
+
if table == 'ticker':
|
1037
|
+
self.handle_ticker(client, message)
|
1038
|
+
if table.find('candles') > -1:
|
1039
|
+
self.handle_ohlcv(client, message)
|
1040
|
+
if table.find('depth') > -1:
|
1041
|
+
self.handle_order_book(client, message)
|
1042
|
+
if table.find('balance') > -1:
|
1043
|
+
self.handle_balance(client, message)
|
1044
|
+
if table.find('position') > -1:
|
1045
|
+
self.handle_positions(client, message)
|
1046
|
+
if table.find('order') > -1:
|
1047
|
+
self.handle_orders(client, message)
|
1048
|
+
if table == 'bestBidAsk':
|
1049
|
+
self.handle_bid_ask(client, message)
|
1050
|
+
else:
|
1051
|
+
if event == 'login':
|
1052
|
+
self.handle_authentication_message(client, message)
|
1053
|
+
if (event == 'placeorder') or (event == 'modifyorder') or (event == 'cancelorder'):
|
1054
|
+
self.handle_place_orders(client, message)
|