ccxt 4.2.35__py2.py3-none-any.whl → 4.2.37__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 +1 -1
- ccxt/abstract/bitfinex2.py +122 -122
- ccxt/async_support/__init__.py +1 -1
- ccxt/async_support/base/exchange.py +1 -1
- ccxt/async_support/binance.py +347 -107
- ccxt/async_support/bitfinex.py +21 -0
- ccxt/async_support/bitfinex2.py +122 -122
- ccxt/async_support/bitget.py +23 -32
- ccxt/async_support/bithumb.py +14 -0
- ccxt/async_support/bitmex.py +22 -3
- ccxt/async_support/bybit.py +11 -4
- ccxt/async_support/woo.py +60 -35
- ccxt/base/exchange.py +1 -1
- ccxt/binance.py +347 -107
- ccxt/bitfinex.py +21 -0
- ccxt/bitfinex2.py +122 -122
- ccxt/bitget.py +23 -32
- ccxt/bithumb.py +14 -0
- ccxt/bitmex.py +22 -3
- ccxt/bybit.py +11 -4
- ccxt/pro/__init__.py +1 -1
- ccxt/pro/binance.py +2 -2
- ccxt/pro/gemini.py +165 -3
- ccxt/test/test_async.py +8 -6
- ccxt/test/test_sync.py +8 -6
- ccxt/woo.py +60 -35
- {ccxt-4.2.35.dist-info → ccxt-4.2.37.dist-info}/METADATA +6 -6
- {ccxt-4.2.35.dist-info → ccxt-4.2.37.dist-info}/RECORD +30 -30
- {ccxt-4.2.35.dist-info → ccxt-4.2.37.dist-info}/WHEEL +0 -0
- {ccxt-4.2.35.dist-info → ccxt-4.2.37.dist-info}/top_level.txt +0 -0
ccxt/async_support/binance.py
CHANGED
@@ -4546,7 +4546,7 @@ class binance(Exchange, ImplicitAPI):
|
|
4546
4546
|
if price is None:
|
4547
4547
|
raise InvalidOrder(self.id + ' editOrder() requires a price argument for a ' + type + ' order')
|
4548
4548
|
request['price'] = self.price_to_precision(symbol, price)
|
4549
|
-
if timeInForceIsRequired:
|
4549
|
+
if timeInForceIsRequired and (self.safe_string(params, 'timeInForce') is None):
|
4550
4550
|
request['timeInForce'] = self.options['defaultTimeInForce'] # 'GTC' = Good To Cancel(default), 'IOC' = Immediate Or Cancel
|
4551
4551
|
if stopPriceIsRequired:
|
4552
4552
|
if stopPrice is None:
|
@@ -4833,19 +4833,155 @@ class binance(Exchange, ImplicitAPI):
|
|
4833
4833
|
# "lastTrade": {"id":"69","time":"1676084430567","price":"24.9","qty":"1.00"},
|
4834
4834
|
# "mmp": False
|
4835
4835
|
# }
|
4836
|
-
#
|
4836
|
+
#
|
4837
4837
|
# cancelOrders/createOrders
|
4838
|
-
#
|
4839
|
-
#
|
4840
|
-
#
|
4838
|
+
#
|
4839
|
+
# {
|
4840
|
+
# "code": -4005,
|
4841
|
+
# "msg": "Quantity greater than max quantity."
|
4842
|
+
# }
|
4843
|
+
#
|
4844
|
+
# createOrder, fetchOpenOrders: portfolio margin linear swap and future
|
4845
|
+
#
|
4846
|
+
# {
|
4847
|
+
# "symbol": "BTCUSDT",
|
4848
|
+
# "side": "BUY",
|
4849
|
+
# "executedQty": "0.000",
|
4850
|
+
# "orderId": 258649539704,
|
4851
|
+
# "goodTillDate": 0,
|
4852
|
+
# "avgPrice": "0",
|
4853
|
+
# "origQty": "0.010",
|
4854
|
+
# "clientOrderId": "x-xcKtGhcu02573c6f15e544e990057b",
|
4855
|
+
# "positionSide": "BOTH",
|
4856
|
+
# "cumQty": "0.000",
|
4857
|
+
# "updateTime": 1707110415436,
|
4858
|
+
# "type": "LIMIT",
|
4859
|
+
# "reduceOnly": False,
|
4860
|
+
# "price": "35000.00",
|
4861
|
+
# "cumQuote": "0.00000",
|
4862
|
+
# "selfTradePreventionMode": "NONE",
|
4863
|
+
# "timeInForce": "GTC",
|
4864
|
+
# "status": "NEW"
|
4865
|
+
# }
|
4866
|
+
#
|
4867
|
+
# createOrder, fetchOpenOrders: portfolio margin inverse swap and future
|
4868
|
+
#
|
4869
|
+
# {
|
4870
|
+
# "symbol": "ETHUSD_PERP",
|
4871
|
+
# "side": "BUY",
|
4872
|
+
# "cumBase": "0",
|
4873
|
+
# "executedQty": "0",
|
4874
|
+
# "orderId": 71275227732,
|
4875
|
+
# "avgPrice": "0.00",
|
4876
|
+
# "origQty": "1",
|
4877
|
+
# "clientOrderId": "x-xcKtGhcuca5af3acfb5044198c5398",
|
4878
|
+
# "positionSide": "BOTH",
|
4879
|
+
# "cumQty": "0",
|
4880
|
+
# "updateTime": 1707110994334,
|
4881
|
+
# "type": "LIMIT",
|
4882
|
+
# "pair": "ETHUSD",
|
4883
|
+
# "reduceOnly": False,
|
4884
|
+
# "price": "2000",
|
4885
|
+
# "timeInForce": "GTC",
|
4886
|
+
# "status": "NEW"
|
4887
|
+
# }
|
4888
|
+
#
|
4889
|
+
# createOrder, fetchOpenOrders: portfolio margin linear swap and future conditional
|
4890
|
+
#
|
4891
|
+
# {
|
4892
|
+
# "newClientStrategyId": "x-xcKtGhcu27f109953d6e4dc0974006",
|
4893
|
+
# "strategyId": 3645916,
|
4894
|
+
# "strategyStatus": "NEW",
|
4895
|
+
# "strategyType": "STOP",
|
4896
|
+
# "origQty": "0.010",
|
4897
|
+
# "price": "35000.00",
|
4898
|
+
# "reduceOnly": False,
|
4899
|
+
# "side": "BUY",
|
4900
|
+
# "positionSide": "BOTH",
|
4901
|
+
# "stopPrice": "45000.00",
|
4902
|
+
# "symbol": "BTCUSDT",
|
4903
|
+
# "timeInForce": "GTC",
|
4904
|
+
# "bookTime": 1707112625879,
|
4905
|
+
# "updateTime": 1707112625879,
|
4906
|
+
# "workingType": "CONTRACT_PRICE",
|
4907
|
+
# "priceProtect": False,
|
4908
|
+
# "goodTillDate": 0,
|
4909
|
+
# "selfTradePreventionMode": "NONE"
|
4910
|
+
# }
|
4911
|
+
#
|
4912
|
+
# createOrder, fetchOpenOrders: portfolio margin inverse swap and future conditional
|
4913
|
+
#
|
4914
|
+
# {
|
4915
|
+
# "newClientStrategyId": "x-xcKtGhcuc6b86f053bb34933850739",
|
4916
|
+
# "strategyId": 1423462,
|
4917
|
+
# "strategyStatus": "NEW",
|
4918
|
+
# "strategyType": "STOP",
|
4919
|
+
# "origQty": "1",
|
4920
|
+
# "price": "2000",
|
4921
|
+
# "reduceOnly": False,
|
4922
|
+
# "side": "BUY",
|
4923
|
+
# "positionSide": "BOTH",
|
4924
|
+
# "stopPrice": "3000",
|
4925
|
+
# "symbol": "ETHUSD_PERP",
|
4926
|
+
# "timeInForce": "GTC",
|
4927
|
+
# "bookTime": 1707113098840,
|
4928
|
+
# "updateTime": 1707113098840,
|
4929
|
+
# "workingType": "CONTRACT_PRICE",
|
4930
|
+
# "priceProtect": False
|
4931
|
+
# }
|
4932
|
+
#
|
4933
|
+
# createOrder, cancelAllOrders: portfolio margin spot margin
|
4934
|
+
#
|
4935
|
+
# {
|
4936
|
+
# "clientOrderId": "x-R4BD3S82e9ef29d8346440f0b28b86",
|
4937
|
+
# "cummulativeQuoteQty": "0.00000000",
|
4938
|
+
# "executedQty": "0.00000000",
|
4939
|
+
# "fills": [],
|
4940
|
+
# "orderId": 24684460474,
|
4941
|
+
# "origQty": "0.00100000",
|
4942
|
+
# "price": "35000.00000000",
|
4943
|
+
# "selfTradePreventionMode": "EXPIRE_MAKER",
|
4944
|
+
# "side": "BUY",
|
4945
|
+
# "status": "NEW",
|
4946
|
+
# "symbol": "BTCUSDT",
|
4947
|
+
# "timeInForce": "GTC",
|
4948
|
+
# "transactTime": 1707113538870,
|
4949
|
+
# "type": "LIMIT"
|
4950
|
+
# }
|
4951
|
+
#
|
4952
|
+
# fetchOpenOrders: portfolio margin spot margin
|
4953
|
+
#
|
4954
|
+
# {
|
4955
|
+
# "symbol": "BTCUSDT",
|
4956
|
+
# "orderId": 24700763749,
|
4957
|
+
# "clientOrderId": "x-R4BD3S826f724c2a4af6425f98c7b6",
|
4958
|
+
# "price": "35000.00000000",
|
4959
|
+
# "origQty": "0.00100000",
|
4960
|
+
# "executedQty": "0.00000000",
|
4961
|
+
# "cummulativeQuoteQty": "0.00000000",
|
4962
|
+
# "status": "NEW",
|
4963
|
+
# "timeInForce": "GTC",
|
4964
|
+
# "type": "LIMIT",
|
4965
|
+
# "side": "BUY",
|
4966
|
+
# "stopPrice": "0.00000000",
|
4967
|
+
# "icebergQty": "0.00000000",
|
4968
|
+
# "time": 1707199187679,
|
4969
|
+
# "updateTime": 1707199187679,
|
4970
|
+
# "isWorking": True,
|
4971
|
+
# "accountId": 200180970,
|
4972
|
+
# "selfTradePreventionMode": "EXPIRE_MAKER",
|
4973
|
+
# "preventedMatchId": null,
|
4974
|
+
# "preventedQuantity": null
|
4975
|
+
# }
|
4841
4976
|
#
|
4842
4977
|
code = self.safe_string(order, 'code')
|
4843
4978
|
if code is not None:
|
4844
4979
|
# cancelOrders/createOrders might have a partial success
|
4845
4980
|
return self.safe_order({'info': order, 'status': 'rejected'}, market)
|
4846
|
-
status = self.parse_order_status(self.
|
4981
|
+
status = self.parse_order_status(self.safe_string_2(order, 'status', 'strategyStatus'))
|
4847
4982
|
marketId = self.safe_string(order, 'symbol')
|
4848
|
-
|
4983
|
+
isContract = ('positionSide' in order) or ('cumQuote' in order)
|
4984
|
+
marketType = 'contract' if isContract else 'spot'
|
4849
4985
|
symbol = self.safe_symbol(marketId, market, None, marketType)
|
4850
4986
|
filled = self.safe_string(order, 'executedQty', '0')
|
4851
4987
|
timestamp = self.safe_integer_n(order, ['time', 'createTime', 'workingTime', 'transactTime', 'updateTime']) # order of the keys matters here
|
@@ -4866,11 +5002,9 @@ class binance(Exchange, ImplicitAPI):
|
|
4866
5002
|
# Note self is not the actual cost, since Binance futures uses leverage to calculate margins.
|
4867
5003
|
cost = self.safe_string_2(order, 'cummulativeQuoteQty', 'cumQuote')
|
4868
5004
|
cost = self.safe_string(order, 'cumBase', cost)
|
4869
|
-
id = self.safe_string(order, 'orderId')
|
4870
5005
|
type = self.safe_string_lower(order, 'type')
|
4871
5006
|
side = self.safe_string_lower(order, 'side')
|
4872
5007
|
fills = self.safe_value(order, 'fills', [])
|
4873
|
-
clientOrderId = self.safe_string(order, 'clientOrderId')
|
4874
5008
|
timeInForce = self.safe_string(order, 'timeInForce')
|
4875
5009
|
if timeInForce == 'GTX':
|
4876
5010
|
# GTX means "Good Till Crossing" and is an equivalent way of saying Post Only
|
@@ -4890,8 +5024,8 @@ class binance(Exchange, ImplicitAPI):
|
|
4890
5024
|
}
|
4891
5025
|
return self.safe_order({
|
4892
5026
|
'info': order,
|
4893
|
-
'id':
|
4894
|
-
'clientOrderId': clientOrderId,
|
5027
|
+
'id': self.safe_string_2(order, 'orderId', 'strategyId'),
|
5028
|
+
'clientOrderId': self.safe_string_2(order, 'clientOrderId', 'newClientStrategyId'),
|
4895
5029
|
'timestamp': timestamp,
|
4896
5030
|
'datetime': self.iso8601(timestamp),
|
4897
5031
|
'lastTradeTimestamp': lastTradeTimestamp,
|
@@ -4996,58 +5130,96 @@ class binance(Exchange, ImplicitAPI):
|
|
4996
5130
|
:see: https://binance-docs.github.io/apidocs/voptions/en/#new-order-trade
|
4997
5131
|
:see: https://binance-docs.github.io/apidocs/spot/en/#new-order-using-sor-trade
|
4998
5132
|
:see: https://binance-docs.github.io/apidocs/spot/en/#test-new-order-using-sor-trade
|
5133
|
+
:see: https://binance-docs.github.io/apidocs/pm/en/#new-um-order-trade
|
5134
|
+
:see: https://binance-docs.github.io/apidocs/pm/en/#new-cm-order-trade
|
5135
|
+
:see: https://binance-docs.github.io/apidocs/pm/en/#new-margin-order-trade
|
5136
|
+
:see: https://binance-docs.github.io/apidocs/pm/en/#new-um-conditional-order-trade
|
5137
|
+
:see: https://binance-docs.github.io/apidocs/pm/en/#new-cm-conditional-order-trade
|
4999
5138
|
:param str symbol: unified symbol of the market to create an order in
|
5000
5139
|
:param str type: 'market' or 'limit' or 'STOP_LOSS' or 'STOP_LOSS_LIMIT' or 'TAKE_PROFIT' or 'TAKE_PROFIT_LIMIT' or 'STOP'
|
5001
5140
|
:param str side: 'buy' or 'sell'
|
5002
|
-
:param float amount: how much of
|
5003
|
-
:param float [price]: the price
|
5141
|
+
:param float amount: how much of you want to trade in units of the base currency
|
5142
|
+
:param float [price]: the price that the order is to be fullfilled, in units of the quote currency, ignored in market orders
|
5004
5143
|
:param dict [params]: extra parameters specific to the exchange API endpoint
|
5144
|
+
:param str [params.reduceOnly]: for swap and future reduceOnly is a string 'true' or 'false' that cant be sent with close position set to True or in hedge mode. For spot margin and option reduceOnly is a boolean.
|
5005
5145
|
:param str [params.marginMode]: 'cross' or 'isolated', for spot margin trading
|
5006
5146
|
:param boolean [params.sor]: *spot only* whether to use SOR(Smart Order Routing) or not, default is False
|
5007
5147
|
:param boolean [params.test]: *spot only* whether to use the test endpoint or not, default is False
|
5008
5148
|
:param float [params.trailingPercent]: the percent to trail away from the current market price
|
5009
5149
|
:param float [params.trailingTriggerPrice]: the price to trigger a trailing order, default uses the price argument
|
5150
|
+
:param float [params.triggerPrice]: the price that a trigger order is triggered at
|
5151
|
+
:param float [params.stopLossPrice]: the price that a stop loss order is triggered at
|
5152
|
+
:param float [params.takeProfitPrice]: the price that a take profit order is triggered at
|
5153
|
+
:param boolean [params.portfolioMargin]: set to True if you would like to create an order in a portfolio margin account
|
5010
5154
|
:returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
|
5011
5155
|
"""
|
5012
5156
|
await self.load_markets()
|
5013
5157
|
market = self.market(symbol)
|
5014
5158
|
marketType = self.safe_string(params, 'type', market['type'])
|
5015
|
-
marginMode
|
5016
|
-
|
5017
|
-
|
5159
|
+
marginMode = None
|
5160
|
+
marginMode, params = self.handle_margin_mode_and_params('createOrder', params)
|
5161
|
+
isPortfolioMargin = None
|
5162
|
+
isPortfolioMargin, params = self.handle_option_and_params_2(params, 'createOrder', 'papi', 'portfolioMargin', False)
|
5163
|
+
triggerPrice = self.safe_string_2(params, 'triggerPrice', 'stopPrice')
|
5164
|
+
stopLossPrice = self.safe_string(params, 'stopLossPrice')
|
5165
|
+
takeProfitPrice = self.safe_string(params, 'takeProfitPrice')
|
5166
|
+
trailingPercent = self.safe_string_2(params, 'trailingPercent', 'callbackRate')
|
5167
|
+
isTrailingPercentOrder = trailingPercent is not None
|
5168
|
+
isStopLoss = stopLossPrice is not None
|
5169
|
+
isTakeProfit = takeProfitPrice is not None
|
5170
|
+
isConditional = (triggerPrice is not None) or isTrailingPercentOrder or isStopLoss or isTakeProfit
|
5171
|
+
sor = self.safe_bool_2(params, 'sor', 'SOR', False)
|
5172
|
+
test = self.safe_bool(params, 'test', False)
|
5173
|
+
params = self.omit(params, ['sor', 'SOR', 'test'])
|
5174
|
+
if isPortfolioMargin:
|
5175
|
+
params['portfolioMargin'] = isPortfolioMargin
|
5018
5176
|
request = self.create_order_request(symbol, type, side, amount, price, params)
|
5019
|
-
|
5020
|
-
if
|
5021
|
-
|
5177
|
+
response = None
|
5178
|
+
if market['option']:
|
5179
|
+
response = await self.eapiPrivatePostOrder(request)
|
5180
|
+
elif sor:
|
5181
|
+
if test:
|
5182
|
+
response = await self.privatePostSorOrderTest(request)
|
5183
|
+
else:
|
5184
|
+
response = await self.privatePostSorOrder(request)
|
5022
5185
|
elif market['linear']:
|
5023
|
-
|
5186
|
+
if isPortfolioMargin:
|
5187
|
+
if isConditional:
|
5188
|
+
response = await self.papiPostUmConditionalOrder(request)
|
5189
|
+
else:
|
5190
|
+
response = await self.papiPostUmOrder(request)
|
5191
|
+
else:
|
5192
|
+
response = await self.fapiPrivatePostOrder(request)
|
5024
5193
|
elif market['inverse']:
|
5025
|
-
|
5194
|
+
if isPortfolioMargin:
|
5195
|
+
if isConditional:
|
5196
|
+
response = await self.papiPostCmConditionalOrder(request)
|
5197
|
+
else:
|
5198
|
+
response = await self.papiPostCmOrder(request)
|
5199
|
+
else:
|
5200
|
+
response = await self.dapiPrivatePostOrder(request)
|
5026
5201
|
elif marketType == 'margin' or marginMode is not None:
|
5027
|
-
|
5028
|
-
|
5029
|
-
|
5030
|
-
|
5031
|
-
|
5032
|
-
test = self.safe_bool(query, 'test', False)
|
5202
|
+
if isPortfolioMargin:
|
5203
|
+
response = await self.papiPostMarginOrder(request)
|
5204
|
+
else:
|
5205
|
+
response = await self.sapiPostMarginOrder(request)
|
5206
|
+
else:
|
5033
5207
|
if test:
|
5034
|
-
|
5035
|
-
|
5208
|
+
response = await self.privatePostOrderTest(request)
|
5209
|
+
else:
|
5210
|
+
response = await self.privatePostOrder(request)
|
5036
5211
|
return self.parse_order(response, market)
|
5037
5212
|
|
5038
5213
|
def create_order_request(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: float = None, params={}):
|
5039
5214
|
"""
|
5040
5215
|
* @ignore
|
5041
|
-
helper function to build request
|
5216
|
+
helper function to build the request
|
5042
5217
|
:param str symbol: unified symbol of the market to create an order in
|
5043
|
-
:param str type: 'market' or 'limit'
|
5218
|
+
:param str type: 'market' or 'limit'
|
5044
5219
|
:param str side: 'buy' or 'sell'
|
5045
|
-
:param float amount: how much
|
5046
|
-
:param float
|
5047
|
-
:param dict params: extra parameters specific to the exchange API endpoint
|
5048
|
-
:param str|None params['marginMode']: 'cross' or 'isolated', for spot margin trading
|
5049
|
-
:param float [params.trailingPercent]: the percent to trail away from the current market price
|
5050
|
-
:param float [params.trailingTriggerPrice]: the price to trigger a trailing order, default uses the price argument
|
5220
|
+
:param float amount: how much you want to trade in units of the base currency
|
5221
|
+
:param float [price]: the price that the order is to be fullfilled, in units of the quote currency, ignored in market orders
|
5222
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
5051
5223
|
:returns dict: request to be sent to the exchange
|
5052
5224
|
"""
|
5053
5225
|
market = self.market(symbol)
|
@@ -5056,31 +5228,35 @@ class binance(Exchange, ImplicitAPI):
|
|
5056
5228
|
initialUppercaseType = type.upper()
|
5057
5229
|
isMarketOrder = initialUppercaseType == 'MARKET'
|
5058
5230
|
isLimitOrder = initialUppercaseType == 'LIMIT'
|
5059
|
-
|
5060
|
-
|
5061
|
-
|
5062
|
-
|
5063
|
-
|
5231
|
+
request = {
|
5232
|
+
'symbol': market['id'],
|
5233
|
+
'side': side.upper(),
|
5234
|
+
}
|
5235
|
+
isPortfolioMargin = None
|
5236
|
+
isPortfolioMargin, params = self.handle_option_and_params_2(params, 'createOrder', 'papi', 'portfolioMargin', False)
|
5237
|
+
marginMode = None
|
5238
|
+
marginMode, params = self.handle_margin_mode_and_params('createOrder', params)
|
5239
|
+
if (marketType == 'margin') or (marginMode is not None) or market['option']:
|
5240
|
+
# for swap and future reduceOnly is a string that cant be sent with close position set to True or in hedge mode
|
5241
|
+
reduceOnly = self.safe_bool(params, 'reduceOnly', False)
|
5242
|
+
params = self.omit(params, 'reduceOnly')
|
5243
|
+
if market['option']:
|
5244
|
+
request['reduceOnly'] = reduceOnly
|
5245
|
+
else:
|
5246
|
+
if reduceOnly:
|
5247
|
+
request['sideEffectType'] = 'AUTO_REPAY'
|
5248
|
+
triggerPrice = self.safe_string_2(params, 'triggerPrice', 'stopPrice')
|
5249
|
+
stopLossPrice = self.safe_string(params, 'stopLossPrice', triggerPrice) # fallback to stopLoss
|
5250
|
+
takeProfitPrice = self.safe_string(params, 'takeProfitPrice')
|
5251
|
+
trailingDelta = self.safe_string(params, 'trailingDelta')
|
5064
5252
|
trailingTriggerPrice = self.safe_string_2(params, 'trailingTriggerPrice', 'activationPrice', self.number_to_string(price))
|
5065
5253
|
trailingPercent = self.safe_string_2(params, 'trailingPercent', 'callbackRate')
|
5066
5254
|
isTrailingPercentOrder = trailingPercent is not None
|
5067
5255
|
isStopLoss = stopLossPrice is not None or trailingDelta is not None
|
5068
5256
|
isTakeProfit = takeProfitPrice is not None
|
5069
|
-
|
5070
|
-
|
5071
|
-
|
5072
|
-
'symbol': market['id'],
|
5073
|
-
'side': side.upper(),
|
5074
|
-
}
|
5075
|
-
if market['spot'] or marketType == 'margin':
|
5076
|
-
# only supported for spot/margin api(all margin markets are spot markets)
|
5077
|
-
if postOnly:
|
5078
|
-
type = 'LIMIT_MAKER'
|
5079
|
-
if marketType == 'margin' or marginMode is not None:
|
5080
|
-
reduceOnly = self.safe_value(params, 'reduceOnly')
|
5081
|
-
if reduceOnly:
|
5082
|
-
request['sideEffectType'] = 'AUTO_REPAY'
|
5083
|
-
params = self.omit(params, 'reduceOnly')
|
5257
|
+
isTriggerOrder = triggerPrice is not None
|
5258
|
+
isConditional = isTriggerOrder or isTrailingPercentOrder or isStopLoss or isTakeProfit
|
5259
|
+
isPortfolioMarginConditional = (isPortfolioMargin and isConditional)
|
5084
5260
|
uppercaseType = type.upper()
|
5085
5261
|
stopPrice = None
|
5086
5262
|
if isTrailingPercentOrder:
|
@@ -5102,31 +5278,41 @@ class binance(Exchange, ImplicitAPI):
|
|
5102
5278
|
uppercaseType = 'TAKE_PROFIT_MARKET' if market['contract'] else 'TAKE_PROFIT'
|
5103
5279
|
elif isLimitOrder:
|
5104
5280
|
uppercaseType = 'TAKE_PROFIT' if market['contract'] else 'TAKE_PROFIT_LIMIT'
|
5105
|
-
if marginMode == 'isolated':
|
5106
|
-
request['isIsolated'] = True
|
5107
|
-
if clientOrderId is None:
|
5108
|
-
broker = self.safe_value(self.options, 'broker', {})
|
5109
|
-
defaultId = 'x-xcKtGhcu' if (market['contract']) else 'x-R4BD3S82'
|
5110
|
-
brokerId = self.safe_string(broker, marketType, defaultId)
|
5111
|
-
request['newClientOrderId'] = brokerId + self.uuid22()
|
5112
|
-
else:
|
5113
|
-
request['newClientOrderId'] = clientOrderId
|
5114
5281
|
if (marketType == 'spot') or (marketType == 'margin'):
|
5115
|
-
request['newOrderRespType'] = self.
|
5282
|
+
request['newOrderRespType'] = self.safe_string(self.options['newOrderRespType'], type, 'RESULT') # 'ACK' for order id, 'RESULT' for full order or 'FULL' for order with fills
|
5116
5283
|
else:
|
5117
5284
|
# swap, futures and options
|
5118
|
-
|
5285
|
+
if not isPortfolioMargin:
|
5286
|
+
request['newOrderRespType'] = 'RESULT' # "ACK", "RESULT", default "ACK"
|
5119
5287
|
if market['option']:
|
5120
5288
|
if type == 'market':
|
5121
5289
|
raise InvalidOrder(self.id + ' ' + type + ' is not a valid order type for the ' + symbol + ' market')
|
5122
5290
|
else:
|
5123
|
-
validOrderTypes = self.
|
5291
|
+
validOrderTypes = self.safe_list(market['info'], 'orderTypes')
|
5124
5292
|
if not self.in_array(uppercaseType, validOrderTypes):
|
5125
5293
|
if initialUppercaseType != uppercaseType:
|
5126
5294
|
raise InvalidOrder(self.id + ' stopPrice parameter is not allowed for ' + symbol + ' ' + type + ' orders')
|
5127
5295
|
else:
|
5128
5296
|
raise InvalidOrder(self.id + ' ' + type + ' is not a valid order type for the ' + symbol + ' market')
|
5129
|
-
|
5297
|
+
clientOrderIdRequest = 'newClientStrategyId' if isPortfolioMarginConditional else 'newClientOrderId'
|
5298
|
+
if clientOrderId is None:
|
5299
|
+
broker = self.safe_dict(self.options, 'broker', {})
|
5300
|
+
defaultId = 'x-xcKtGhcu' if (market['contract']) else 'x-R4BD3S82'
|
5301
|
+
brokerId = self.safe_string(broker, marketType, defaultId)
|
5302
|
+
request[clientOrderIdRequest] = brokerId + self.uuid22()
|
5303
|
+
else:
|
5304
|
+
request[clientOrderIdRequest] = clientOrderId
|
5305
|
+
postOnly = None
|
5306
|
+
if not isPortfolioMargin:
|
5307
|
+
postOnly = self.is_post_only(isMarketOrder, initialUppercaseType == 'LIMIT_MAKER', params)
|
5308
|
+
if market['spot'] or marketType == 'margin':
|
5309
|
+
# only supported for spot/margin api(all margin markets are spot markets)
|
5310
|
+
if postOnly:
|
5311
|
+
uppercaseType = 'LIMIT_MAKER'
|
5312
|
+
if marginMode == 'isolated':
|
5313
|
+
request['isIsolated'] = True
|
5314
|
+
typeRequest = 'strategyType' if isPortfolioMarginConditional else 'type'
|
5315
|
+
request[typeRequest] = uppercaseType
|
5130
5316
|
# additional required fields depending on the order type
|
5131
5317
|
timeInForceIsRequired = False
|
5132
5318
|
priceIsRequired = False
|
@@ -5154,9 +5340,9 @@ class binance(Exchange, ImplicitAPI):
|
|
5154
5340
|
#
|
5155
5341
|
if uppercaseType == 'MARKET':
|
5156
5342
|
if market['spot']:
|
5157
|
-
quoteOrderQty = self.
|
5343
|
+
quoteOrderQty = self.safe_bool(self.options, 'quoteOrderQty', True)
|
5158
5344
|
if quoteOrderQty:
|
5159
|
-
quoteOrderQtyNew = self.
|
5345
|
+
quoteOrderQtyNew = self.safe_string_2(params, 'quoteOrderQty', 'cost')
|
5160
5346
|
precision = market['precision']['price']
|
5161
5347
|
if quoteOrderQtyNew is not None:
|
5162
5348
|
request['quoteOrderQty'] = self.decimal_to_precision(quoteOrderQtyNew, TRUNCATE, precision, self.precisionMode)
|
@@ -5193,7 +5379,7 @@ class binance(Exchange, ImplicitAPI):
|
|
5193
5379
|
stopPriceIsRequired = True
|
5194
5380
|
priceIsRequired = True
|
5195
5381
|
elif (uppercaseType == 'STOP_MARKET') or (uppercaseType == 'TAKE_PROFIT_MARKET'):
|
5196
|
-
closePosition = self.
|
5382
|
+
closePosition = self.safe_bool(params, 'closePosition')
|
5197
5383
|
if closePosition is None:
|
5198
5384
|
quantityIsRequired = True
|
5199
5385
|
stopPriceIsRequired = True
|
@@ -5202,15 +5388,15 @@ class binance(Exchange, ImplicitAPI):
|
|
5202
5388
|
if trailingPercent is None:
|
5203
5389
|
raise InvalidOrder(self.id + ' createOrder() requires a trailingPercent param for a ' + type + ' order')
|
5204
5390
|
if quantityIsRequired:
|
5205
|
-
|
5391
|
+
# portfolio margin has a different amount precision
|
5392
|
+
if isPortfolioMargin:
|
5393
|
+
request['quantity'] = self.parse_to_numeric(amount)
|
5394
|
+
else:
|
5395
|
+
request['quantity'] = self.amount_to_precision(symbol, amount)
|
5206
5396
|
if priceIsRequired:
|
5207
5397
|
if price is None:
|
5208
5398
|
raise InvalidOrder(self.id + ' createOrder() requires a price argument for a ' + type + ' order')
|
5209
5399
|
request['price'] = self.price_to_precision(symbol, price)
|
5210
|
-
if timeInForceIsRequired:
|
5211
|
-
request['timeInForce'] = self.options['defaultTimeInForce'] # 'GTC' = Good To Cancel(default), 'IOC' = Immediate Or Cancel
|
5212
|
-
if market['contract'] and postOnly:
|
5213
|
-
request['timeInForce'] = 'GTX'
|
5214
5400
|
if stopPriceIsRequired:
|
5215
5401
|
if market['contract']:
|
5216
5402
|
if stopPrice is None:
|
@@ -5221,10 +5407,14 @@ class binance(Exchange, ImplicitAPI):
|
|
5221
5407
|
raise InvalidOrder(self.id + ' createOrder() requires a stopPrice or trailingDelta param for a ' + type + ' order')
|
5222
5408
|
if stopPrice is not None:
|
5223
5409
|
request['stopPrice'] = self.price_to_precision(symbol, stopPrice)
|
5410
|
+
if timeInForceIsRequired and (self.safe_string(params, 'timeInForce') is None):
|
5411
|
+
request['timeInForce'] = self.options['defaultTimeInForce'] # 'GTC' = Good To Cancel(default), 'IOC' = Immediate Or Cancel
|
5412
|
+
if not isPortfolioMargin and market['contract'] and postOnly:
|
5413
|
+
request['timeInForce'] = 'GTX'
|
5224
5414
|
# remove timeInForce from params because PO is only used by self.is_post_onlyand it's not a valid value for Binance
|
5225
5415
|
if self.safe_string(params, 'timeInForce') == 'PO':
|
5226
|
-
params = self.omit(params,
|
5227
|
-
requestParams = self.omit(params, ['
|
5416
|
+
params = self.omit(params, 'timeInForce')
|
5417
|
+
requestParams = self.omit(params, ['type', 'newClientOrderId', 'clientOrderId', 'postOnly', 'stopLossPrice', 'takeProfitPrice', 'stopPrice', 'triggerPrice', 'trailingTriggerPrice', 'trailingPercent', 'quoteOrderQty', 'cost', 'test'])
|
5228
5418
|
return self.extend(request, requestParams)
|
5229
5419
|
|
5230
5420
|
async def create_market_order_with_cost(self, symbol: str, side: OrderSide, cost, params={}):
|
@@ -5453,21 +5643,28 @@ class binance(Exchange, ImplicitAPI):
|
|
5453
5643
|
|
5454
5644
|
async def fetch_open_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
|
5455
5645
|
"""
|
5646
|
+
fetch all unfilled currently open orders
|
5456
5647
|
:see: https://binance-docs.github.io/apidocs/spot/en/#cancel-an-existing-order-and-send-a-new-order-trade
|
5457
5648
|
:see: https://binance-docs.github.io/apidocs/futures/en/#current-all-open-orders-user_data
|
5458
5649
|
:see: https://binance-docs.github.io/apidocs/delivery/en/#current-all-open-orders-user_data
|
5459
5650
|
:see: https://binance-docs.github.io/apidocs/voptions/en/#query-current-open-option-orders-user_data
|
5460
|
-
fetch all unfilled currently open orders
|
5461
5651
|
:see: https://binance-docs.github.io/apidocs/spot/en/#current-open-orders-user_data
|
5462
5652
|
:see: https://binance-docs.github.io/apidocs/futures/en/#current-all-open-orders-user_data
|
5463
5653
|
:see: https://binance-docs.github.io/apidocs/delivery/en/#current-all-open-orders-user_data
|
5464
5654
|
:see: https://binance-docs.github.io/apidocs/voptions/en/#query-current-open-option-orders-user_data
|
5465
5655
|
:see: https://binance-docs.github.io/apidocs/spot/en/#query-margin-account-39-s-open-orders-user_data
|
5656
|
+
:see: https://binance-docs.github.io/apidocs/pm/en/#query-all-current-um-open-orders-user_data
|
5657
|
+
:see: https://binance-docs.github.io/apidocs/pm/en/#query-all-current-cm-open-orders-user_data
|
5658
|
+
:see: https://binance-docs.github.io/apidocs/pm/en/#query-all-current-um-open-conditional-orders-user_data
|
5659
|
+
:see: https://binance-docs.github.io/apidocs/pm/en/#query-all-current-cm-open-conditional-orders-user_data
|
5660
|
+
:see: https://binance-docs.github.io/apidocs/pm/en/#query-current-margin-open-order-user_data
|
5466
5661
|
:param str symbol: unified market symbol
|
5467
5662
|
:param int [since]: the earliest time in ms to fetch open orders for
|
5468
5663
|
:param int [limit]: the maximum number of open orders structures to retrieve
|
5469
5664
|
:param dict [params]: extra parameters specific to the exchange API endpoint
|
5470
5665
|
:param str [params.marginMode]: 'cross' or 'isolated', for spot margin trading
|
5666
|
+
:param boolean [params.portfolioMargin]: set to True if you would like to fetch open orders in the portfolio margin account
|
5667
|
+
:param boolean [params.stop]: set to True if you would like to fetch portfolio margin account conditional orders
|
5471
5668
|
:returns Order[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
|
5472
5669
|
"""
|
5473
5670
|
await self.load_markets()
|
@@ -5475,14 +5672,16 @@ class binance(Exchange, ImplicitAPI):
|
|
5475
5672
|
type = None
|
5476
5673
|
request = {}
|
5477
5674
|
marginMode = None
|
5478
|
-
|
5479
|
-
|
5675
|
+
marginMode, params = self.handle_margin_mode_and_params('fetchOpenOrders', params)
|
5676
|
+
isPortfolioMargin = None
|
5677
|
+
isPortfolioMargin, params = self.handle_option_and_params_2(params, 'fetchOpenOrders', 'papi', 'portfolioMargin', False)
|
5678
|
+
isConditional = self.safe_bool_2(params, 'stop', 'conditional')
|
5480
5679
|
if symbol is not None:
|
5481
5680
|
market = self.market(symbol)
|
5482
5681
|
request['symbol'] = market['id']
|
5483
5682
|
defaultType = self.safe_string_2(self.options, 'fetchOpenOrders', 'defaultType', 'spot')
|
5484
5683
|
marketType = market['type'] if ('type' in market) else defaultType
|
5485
|
-
type = self.safe_string(
|
5684
|
+
type = self.safe_string(params, 'type', marketType)
|
5486
5685
|
elif self.options['warnOnFetchOpenOrdersWithoutSymbol']:
|
5487
5686
|
symbols = self.symbols
|
5488
5687
|
numSymbols = len(symbols)
|
@@ -5490,29 +5689,44 @@ class binance(Exchange, ImplicitAPI):
|
|
5490
5689
|
raise ExchangeError(self.id + ' fetchOpenOrders() WARNING: fetching open orders without specifying a symbol is rate-limited to one call per ' + str(fetchOpenOrdersRateLimit) + ' seconds. Do not call self method frequently to avoid ban. Set ' + self.id + '.options["warnOnFetchOpenOrdersWithoutSymbol"] = False to suppress self warning message.')
|
5491
5690
|
else:
|
5492
5691
|
defaultType = self.safe_string_2(self.options, 'fetchOpenOrders', 'defaultType', 'spot')
|
5493
|
-
type = self.safe_string(
|
5692
|
+
type = self.safe_string(params, 'type', defaultType)
|
5494
5693
|
subType = None
|
5495
|
-
subType,
|
5496
|
-
|
5694
|
+
subType, params = self.handle_sub_type_and_params('fetchOpenOrders', market, params)
|
5695
|
+
params = self.omit(params, ['type', 'stop', 'conditional'])
|
5497
5696
|
response = None
|
5498
5697
|
if type == 'option':
|
5499
5698
|
if since is not None:
|
5500
5699
|
request['startTime'] = since
|
5501
5700
|
if limit is not None:
|
5502
5701
|
request['limit'] = limit
|
5503
|
-
response = await self.eapiPrivateGetOpenOrders(self.extend(request,
|
5702
|
+
response = await self.eapiPrivateGetOpenOrders(self.extend(request, params))
|
5504
5703
|
elif self.is_linear(type, subType):
|
5505
|
-
|
5704
|
+
if isPortfolioMargin:
|
5705
|
+
if isConditional:
|
5706
|
+
response = await self.papiGetUmConditionalOpenOrders(self.extend(request, params))
|
5707
|
+
else:
|
5708
|
+
response = await self.papiGetUmOpenOrders(self.extend(request, params))
|
5709
|
+
else:
|
5710
|
+
response = await self.fapiPrivateGetOpenOrders(self.extend(request, params))
|
5506
5711
|
elif self.is_inverse(type, subType):
|
5507
|
-
|
5712
|
+
if isPortfolioMargin:
|
5713
|
+
if isConditional:
|
5714
|
+
response = await self.papiGetCmConditionalOpenOrders(self.extend(request, params))
|
5715
|
+
else:
|
5716
|
+
response = await self.papiGetCmOpenOrders(self.extend(request, params))
|
5717
|
+
else:
|
5718
|
+
response = await self.dapiPrivateGetOpenOrders(self.extend(request, params))
|
5508
5719
|
elif type == 'margin' or marginMode is not None:
|
5509
|
-
if
|
5510
|
-
|
5511
|
-
|
5512
|
-
|
5513
|
-
|
5720
|
+
if isPortfolioMargin:
|
5721
|
+
response = await self.papiGetMarginOpenOrders(self.extend(request, params))
|
5722
|
+
else:
|
5723
|
+
if marginMode == 'isolated':
|
5724
|
+
request['isIsolated'] = True
|
5725
|
+
if symbol is None:
|
5726
|
+
raise ArgumentsRequired(self.id + ' fetchOpenOrders() requires a symbol argument for isolated markets')
|
5727
|
+
response = await self.sapiGetMarginOpenOrders(self.extend(request, params))
|
5514
5728
|
else:
|
5515
|
-
response = await self.privateGetOpenOrders(self.extend(request,
|
5729
|
+
response = await self.privateGetOpenOrders(self.extend(request, params))
|
5516
5730
|
return self.parse_orders(response, market, since, limit)
|
5517
5731
|
|
5518
5732
|
async def fetch_closed_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
|
@@ -5608,40 +5822,66 @@ class binance(Exchange, ImplicitAPI):
|
|
5608
5822
|
|
5609
5823
|
async def cancel_all_orders(self, symbol: Str = None, params={}):
|
5610
5824
|
"""
|
5825
|
+
cancel all open orders in a market
|
5611
5826
|
:see: https://binance-docs.github.io/apidocs/spot/en/#cancel-all-open-orders-on-a-symbol-trade
|
5612
5827
|
:see: https://binance-docs.github.io/apidocs/futures/en/#cancel-all-open-orders-trade
|
5613
5828
|
:see: https://binance-docs.github.io/apidocs/delivery/en/#cancel-all-open-orders-trade
|
5614
5829
|
:see: https://binance-docs.github.io/apidocs/voptions/en/#cancel-all-option-orders-on-specific-symbol-trade
|
5615
5830
|
:see: https://binance-docs.github.io/apidocs/spot/en/#margin-account-cancel-order-trade
|
5616
|
-
cancel
|
5831
|
+
:see: https://binance-docs.github.io/apidocs/pm/en/#cancel-all-um-open-orders-trade
|
5832
|
+
:see: https://binance-docs.github.io/apidocs/pm/en/#cancel-all-cm-open-orders-trade
|
5833
|
+
:see: https://binance-docs.github.io/apidocs/pm/en/#cancel-all-um-open-conditional-orders-trade
|
5834
|
+
:see: https://binance-docs.github.io/apidocs/pm/en/#cancel-all-cm-open-conditional-orders-trade
|
5835
|
+
:see: https://binance-docs.github.io/apidocs/pm/en/#cancel-margin-account-all-open-orders-on-a-symbol-trade
|
5617
5836
|
:param str symbol: unified market symbol of the market to cancel orders in
|
5618
5837
|
:param dict [params]: extra parameters specific to the exchange API endpoint
|
5619
5838
|
:param str [params.marginMode]: 'cross' or 'isolated', for spot margin trading
|
5839
|
+
:param boolean [params.portfolioMargin]: set to True if you would like to cancel orders in a portfolio margin account
|
5840
|
+
:param boolean [params.stop]: set to True if you would like to cancel portfolio margin account conditional orders
|
5620
5841
|
:returns dict[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
|
5621
5842
|
"""
|
5622
5843
|
if symbol is None:
|
5623
|
-
raise ArgumentsRequired(self.id + '
|
5844
|
+
raise ArgumentsRequired(self.id + ' cancelAllOrders() requires a symbol argument')
|
5624
5845
|
await self.load_markets()
|
5625
5846
|
market = self.market(symbol)
|
5626
5847
|
request = {
|
5627
5848
|
'symbol': market['id'],
|
5628
5849
|
}
|
5850
|
+
isPortfolioMargin = None
|
5851
|
+
isPortfolioMargin, params = self.handle_option_and_params_2(params, 'cancelAllOrders', 'papi', 'portfolioMargin', False)
|
5852
|
+
isConditional = self.safe_bool_2(params, 'stop', 'conditional')
|
5629
5853
|
type = self.safe_string(params, 'type', market['type'])
|
5630
|
-
params = self.omit(params, ['type'])
|
5631
|
-
marginMode
|
5854
|
+
params = self.omit(params, ['type', 'stop', 'conditional'])
|
5855
|
+
marginMode = None
|
5856
|
+
marginMode, params = self.handle_margin_mode_and_params('cancelAllOrders', params)
|
5632
5857
|
response = None
|
5633
5858
|
if market['option']:
|
5634
|
-
response = await self.eapiPrivateDeleteAllOpenOrders(self.extend(request,
|
5859
|
+
response = await self.eapiPrivateDeleteAllOpenOrders(self.extend(request, params))
|
5635
5860
|
elif market['linear']:
|
5636
|
-
|
5861
|
+
if isPortfolioMargin:
|
5862
|
+
if isConditional:
|
5863
|
+
response = await self.papiDeleteUmConditionalAllOpenOrders(self.extend(request, params))
|
5864
|
+
else:
|
5865
|
+
response = await self.papiDeleteUmAllOpenOrders(self.extend(request, params))
|
5866
|
+
else:
|
5867
|
+
response = await self.fapiPrivateDeleteAllOpenOrders(self.extend(request, params))
|
5637
5868
|
elif market['inverse']:
|
5638
|
-
|
5869
|
+
if isPortfolioMargin:
|
5870
|
+
if isConditional:
|
5871
|
+
response = await self.papiDeleteCmConditionalAllOpenOrders(self.extend(request, params))
|
5872
|
+
else:
|
5873
|
+
response = await self.papiDeleteCmAllOpenOrders(self.extend(request, params))
|
5874
|
+
else:
|
5875
|
+
response = await self.dapiPrivateDeleteAllOpenOrders(self.extend(request, params))
|
5639
5876
|
elif (type == 'margin') or (marginMode is not None):
|
5640
|
-
if
|
5641
|
-
|
5642
|
-
|
5877
|
+
if isPortfolioMargin:
|
5878
|
+
response = await self.papiDeleteMarginAllOpenOrders(self.extend(request, params))
|
5879
|
+
else:
|
5880
|
+
if marginMode == 'isolated':
|
5881
|
+
request['isIsolated'] = True
|
5882
|
+
response = await self.sapiDeleteMarginOpenOrders(self.extend(request, params))
|
5643
5883
|
else:
|
5644
|
-
response = await self.privateDeleteOpenOrders(self.extend(request,
|
5884
|
+
response = await self.privateDeleteOpenOrders(self.extend(request, params))
|
5645
5885
|
if isinstance(response, list):
|
5646
5886
|
return self.parse_orders(response, market)
|
5647
5887
|
else:
|