Skip to content

Commit 17c58e1

Browse files
authored
Merge pull request #1467 from Drakkar-Software/dev
Master update
2 parents 729b398 + 806a6dd commit 17c58e1

File tree

11 files changed

+45
-113
lines changed

11 files changed

+45
-113
lines changed

Trading/Exchange/binance/binance_exchange.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,9 @@ class Binance(exchanges.RestExchange):
3939
# binance {"code":-4048,"msg":"Margin type cannot be changed if there exists position."}
4040
# Set True when the "limit" param when fetching order books is taken into account
4141
SUPPORTS_CUSTOM_LIMIT_ORDER_BOOK_FETCH = True
42+
# set True when create_market_buy_order_with_cost should be used to create buy market orders
43+
# (useful to predict the exact spent amount)
44+
ENABLE_SPOT_BUY_MARKET_WITH_COST = True
4245

4346
# should be overridden locally to match exchange support
4447
SUPPORTED_ELEMENTS = {
@@ -167,7 +170,7 @@ def get_supported_exchange_types(cls) -> list:
167170
def get_additional_connector_config(self):
168171
config = {
169172
ccxt_constants.CCXT_OPTIONS: {
170-
"quoteOrderQty": False, # disable quote conversion
173+
"quoteOrderQty": True, # enable quote conversion for market orders
171174
"recvWindow": 60000, # default is 10000, avoid time related issues
172175
"fetchPositions": "account", # required to fetch empty positions as well
173176
"filterClosed": False, # return empty positions as well
@@ -216,6 +219,14 @@ async def create_order(self, order_type: trading_enums.TraderOrderType, symbol:
216219
side=side, current_price=current_price,
217220
reduce_only=reduce_only, params=params)
218221

222+
async def _create_market_sell_order(
223+
self, symbol, quantity, price=None, reduce_only: bool = False, params=None
224+
) -> dict:
225+
# force price to None to avoid selling using quote amount (force market sell quantity in base amount)
226+
return await super()._create_market_sell_order(
227+
symbol, quantity, price=None, reduce_only=reduce_only, params=params
228+
)
229+
219230
async def set_symbol_partial_take_profit_stop_loss(self, symbol: str, inverse: bool,
220231
tp_sl_mode: trading_enums.TakeProfitStopLossMode):
221232
"""

Trading/Exchange/bitget/bitget_exchange.py

Lines changed: 3 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -13,20 +13,19 @@
1313
#
1414
# You should have received a copy of the GNU Lesser General Public
1515
# License along with this library.
16-
import decimal
17-
import typing
18-
1916
import octobot_trading.exchanges as exchanges
2017
import octobot_trading.exchanges.connectors.ccxt.constants as ccxt_constants
2118
import octobot_trading.enums as trading_enums
22-
import octobot_trading.errors
2319

2420

2521
class Bitget(exchanges.RestExchange):
2622
DESCRIPTION = ""
2723

2824
FIX_MARKET_STATUS = True
2925
REMOVE_MARKET_STATUS_PRICE_LIMITS = True
26+
# set True when create_market_buy_order_with_cost should be used to create buy market orders
27+
# (useful to predict the exact spent amount)
28+
ENABLE_SPOT_BUY_MARKET_WITH_COST = True
3029

3130
@classmethod
3231
def get_name(cls):
@@ -44,22 +43,6 @@ def get_additional_connector_config(self):
4443
}
4544
}
4645

47-
async def create_order(self, order_type: trading_enums.TraderOrderType, symbol: str, quantity: decimal.Decimal,
48-
price: decimal.Decimal = None, stop_price: decimal.Decimal = None,
49-
side: trading_enums.TradeOrderSide = None, current_price: decimal.Decimal = None,
50-
reduce_only: bool = False, params: dict = None) -> typing.Optional[dict]:
51-
if order_type is trading_enums.TraderOrderType.BUY_MARKET:
52-
# on Bitget, market orders are in quote currency (YYY in XYZ/YYY)
53-
used_price = price or current_price
54-
if not used_price:
55-
raise octobot_trading.errors.NotSupported(f"{self.get_name()} requires a price parameter to create "
56-
f"market orders as quantity is in quote currency")
57-
quantity = quantity * used_price
58-
return await super().create_order(order_type, symbol, quantity,
59-
price=price, stop_price=stop_price,
60-
side=side, current_price=current_price,
61-
reduce_only=reduce_only, params=params)
62-
6346

6447
class BitgetCCXTAdapter(exchanges.CCXTAdapter):
6548

Trading/Exchange/bitmart/bitmart_exchange.py

Lines changed: 9 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,10 @@
1313
#
1414
# You should have received a copy of the GNU Lesser General Public
1515
# License along with this library.
16-
import decimal
17-
import typing
18-
1916
import octobot_trading.exchanges as exchanges
2017
import octobot_trading.exchanges.connectors.ccxt.constants as ccxt_constants
2118
import octobot_trading.enums as trading_enums
22-
import octobot_trading.errors
19+
import octobot_trading.constants as trading_constants
2320

2421

2522
class BitMartConnector(exchanges.CCXTConnector):
@@ -36,6 +33,11 @@ class BitMart(exchanges.RestExchange):
3633
FIX_MARKET_STATUS = True
3734
DEFAULT_CONNECTOR_CLASS = BitMartConnector
3835
REQUIRE_ORDER_FEES_FROM_TRADES = True # set True when get_order is not giving fees on closed orders and fees
36+
# set True when create_market_buy_order_with_cost should be used to create buy market orders
37+
# (useful to predict the exact spent amount)
38+
ENABLE_SPOT_BUY_MARKET_WITH_COST = True
39+
# broken: need v4 endpoint required, 13/03/25 ccxt still doesn't have it
40+
SUPPORT_FETCHING_CANCELLED_ORDERS = False
3941

4042
@classmethod
4143
def get_name(cls):
@@ -53,21 +55,9 @@ def get_additional_connector_config(self):
5355
}
5456
}
5557

56-
async def create_order(self, order_type: trading_enums.TraderOrderType, symbol: str, quantity: decimal.Decimal,
57-
price: decimal.Decimal = None, stop_price: decimal.Decimal = None,
58-
side: trading_enums.TradeOrderSide = None, current_price: decimal.Decimal = None,
59-
reduce_only: bool = False, params: dict = None) -> typing.Optional[dict]:
60-
if order_type is trading_enums.TraderOrderType.BUY_MARKET:
61-
# on BitMart, market orders are in quote currency (YYY in XYZ/YYY)
62-
used_price = price or current_price
63-
if not used_price:
64-
raise octobot_trading.errors.NotSupported(f"{self.get_name()} requires a price parameter to create "
65-
f"market orders as quantity is in quote currency")
66-
quantity = quantity * used_price
67-
return await super().create_order(order_type, symbol, quantity,
68-
price=price, stop_price=stop_price,
69-
side=side, current_price=current_price,
70-
reduce_only=reduce_only, params=params)
58+
async def get_account_id(self, **kwargs: dict) -> str:
59+
# not available on bitmart
60+
return trading_constants.DEFAULT_ACCOUNT_ID
7161

7262

7363
class BitMartCCXTAdapter(exchanges.CCXTAdapter):

Trading/Exchange/bybit/bybit_exchange.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,7 @@ async def create_order(self, order_type: trading_enums.TraderOrderType, symbol:
187187
side: trading_enums.TradeOrderSide = None, current_price: decimal.Decimal = None,
188188
reduce_only: bool = False, params: dict = None) -> typing.Optional[dict]:
189189
if not self.exchange_manager.is_future:
190+
# should be replacable by ENABLE_SPOT_BUY_MARKET_WITH_COST = True => check when upgrading to unified
190191
if order_type is trading_enums.TraderOrderType.BUY_MARKET:
191192
# on Bybit, market orders are in quote currency (YYY in XYZ/YYY)
192193
used_price = price or current_price

Trading/Exchange/coinbase/coinbase_exchange.py

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,9 @@ class Coinbase(exchanges.RestExchange):
106106
INSTANT_RETRY_ERROR_CODE = "429"
107107

108108
FIX_MARKET_STATUS = True
109+
# set True when create_market_buy_order_with_cost should be used to create buy market orders
110+
# (useful to predict the exact spent amount)
111+
ENABLE_SPOT_BUY_MARKET_WITH_COST = True
109112

110113
# text content of errors due to orders not found errors
111114
EXCHANGE_ORDER_NOT_FOUND_ERRORS: typing.List[typing.Iterable[str]] = [
@@ -265,18 +268,6 @@ async def get_all_currencies_price_ticker(self, **kwargs: dict) -> typing.Option
265268
# override for retrier
266269
return await super().get_all_currencies_price_ticker(**kwargs)
267270

268-
async def create_order(self, order_type: trading_enums.TraderOrderType, symbol: str, quantity: decimal.Decimal,
269-
price: decimal.Decimal = None, stop_price: decimal.Decimal = None,
270-
side: trading_enums.TradeOrderSide = None, current_price: decimal.Decimal = None,
271-
reduce_only: bool = False, params: dict = None) -> typing.Optional[dict]:
272-
# ccxt is converting quantity using price, make sure it's available
273-
if order_type is trading_enums.TraderOrderType.BUY_MARKET and not current_price:
274-
raise octobot_trading.errors.NotSupported(f"current_price is required for {order_type} orders")
275-
return await super().create_order(order_type, symbol, quantity,
276-
price=price, stop_price=stop_price,
277-
side=side, current_price=current_price,
278-
reduce_only=reduce_only, params=params)
279-
280271
@_coinbase_retrier
281272
async def cancel_order(
282273
self, exchange_order_id: str, symbol: str, order_type: trading_enums.TraderOrderType, **kwargs: dict

Trading/Exchange/coinex/coinex_exchange.py

Lines changed: 3 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,11 @@
1313
#
1414
# You should have received a copy of the GNU Lesser General Public
1515
# License along with this library.
16-
import decimal
1716
import typing
1817

1918
import octobot_trading.exchanges as exchanges
2019
import octobot_trading.exchanges.connectors.ccxt.constants as ccxt_constants
2120
import octobot_trading.enums as trading_enums
22-
import octobot_trading.errors
2321
import octobot_trading.constants as constants
2422

2523

@@ -36,6 +34,9 @@ class Coinex(exchanges.RestExchange):
3634
("order not found", )
3735
]
3836
SUPPORT_FETCHING_CANCELLED_ORDERS = False
37+
# set True when create_market_buy_order_with_cost should be used to create buy market orders
38+
# (useful to predict the exact spent amount)
39+
ENABLE_SPOT_BUY_MARKET_WITH_COST = True
3940

4041
@classmethod
4142
def get_name(cls):
@@ -80,21 +81,6 @@ async def get_closed_orders(self, symbol=None, since=None, limit=None, **kwargs)
8081
limit=self._fix_limit(limit),
8182
**kwargs)
8283

83-
async def create_order(self, order_type: trading_enums.TraderOrderType, symbol: str, quantity: decimal.Decimal,
84-
price: decimal.Decimal = None, stop_price: decimal.Decimal = None,
85-
side: trading_enums.TradeOrderSide = None, current_price: decimal.Decimal = None,
86-
reduce_only: bool = False, params: dict = None) -> typing.Optional[dict]:
87-
if order_type is trading_enums.TraderOrderType.BUY_MARKET:
88-
# on coinex, market orders are in quote currency (YYY in XYZ/YYY)
89-
if price is None:
90-
raise octobot_trading.errors.NotSupported(f"{self.get_name()} requires a price parameter to create "
91-
f"market orders as quantity is in quote currency")
92-
quantity = quantity * price
93-
return await super().create_order(order_type, symbol, quantity,
94-
price=price, stop_price=stop_price,
95-
side=side, current_price=current_price,
96-
reduce_only=reduce_only, params=params)
97-
9884
def _fix_limit(self, limit: int) -> int:
9985
return min(self.MAX_PAGINATION_LIMIT, limit) if limit else limit
10086

Trading/Exchange/htx/htx_exchange.py

Lines changed: 3 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -13,18 +13,16 @@
1313
#
1414
# You should have received a copy of the GNU Lesser General Public
1515
# License along with this library.
16-
import decimal
17-
import typing
18-
1916
import octobot_trading.exchanges as exchanges
2017
import octobot_trading.exchanges.connectors.ccxt.constants as ccxt_constants
21-
import octobot_trading.enums as trading_enums
22-
import octobot_trading.errors
2318

2419

2520
class Htx(exchanges.RestExchange):
2621
FIX_MARKET_STATUS = True
2722
REMOVE_MARKET_STATUS_PRICE_LIMITS = True
23+
# set True when create_market_buy_order_with_cost should be used to create buy market orders
24+
# (useful to predict the exact spent amount)
25+
ENABLE_SPOT_BUY_MARKET_WITH_COST = True
2826

2927
@classmethod
3028
def get_name(cls):
@@ -49,22 +47,6 @@ async def get_symbol_prices(self, symbol, time_frame, limit: int = 500, **kwargs
4947
kwargs[history_param] = False
5048
return await super().get_symbol_prices(symbol, time_frame, limit=limit, **kwargs)
5149

52-
async def create_order(self, order_type: trading_enums.TraderOrderType, symbol: str, quantity: decimal.Decimal,
53-
price: decimal.Decimal = None, stop_price: decimal.Decimal = None,
54-
side: trading_enums.TradeOrderSide = None, current_price: decimal.Decimal = None,
55-
reduce_only: bool = False, params: dict = None) -> typing.Optional[dict]:
56-
if order_type is trading_enums.TraderOrderType.BUY_MARKET:
57-
# on HTX, market orders are in quote currency (YYY in XYZ/YYY)
58-
used_price = price or current_price
59-
if not used_price:
60-
raise octobot_trading.errors.NotSupported(f"{self.get_name()} requires a price parameter to create "
61-
f"market orders as quantity is in quote currency")
62-
quantity = quantity * used_price
63-
return await super().create_order(order_type, symbol, quantity,
64-
price=price, stop_price=stop_price,
65-
side=side, current_price=current_price,
66-
reduce_only=reduce_only, params=params)
67-
6850

6951
class HtxCCXTAdapter(exchanges.CCXTAdapter):
7052

Trading/Exchange/kucoin/kucoin_exchange.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@
2525
import octobot_trading.exchanges.connectors.ccxt.ccxt_connector as ccxt_connector
2626
import octobot_trading.exchanges.connectors.ccxt.enums as ccxt_enums
2727
import octobot_trading.exchanges.connectors.ccxt.constants as ccxt_constants
28-
import octobot_trading.exchanges.connectors.ccxt.ccxt_client_util as ccxt_client_util
2928
import octobot_commons.constants as commons_constants
3029
import octobot_trading.constants as constants
3130
import octobot_trading.enums as trading_enums
@@ -88,6 +87,9 @@ class Kucoin(exchanges.RestExchange):
8887
INSTANT_RETRY_ERROR_CODE = "429000"
8988
FUTURES_CCXT_CLASS_NAME = "kucoinfutures"
9089
MAX_INCREASED_POSITION_QUANTITY_MULTIPLIER = decimal.Decimal("0.95")
90+
# set True when create_market_buy_order_with_cost should be used to create buy market orders
91+
# (useful to predict the exact spent amount)
92+
ENABLE_SPOT_BUY_MARKET_WITH_COST = True
9193

9294
# set True when get_positions() is not returning empty positions and should use get_position() instead
9395
REQUIRES_SYMBOL_FOR_EMPTY_POSITION = True
@@ -273,6 +275,7 @@ async def get_recent_trades(self, symbol, limit=50, **kwargs):
273275
# filtered by limit before reversing (or most recent trades are lost)
274276
recent_trades = await super().get_recent_trades(symbol, limit=None, **kwargs)
275277
return recent_trades[::-1][:limit] if recent_trades else []
278+
276279
@_kucoin_retrier
277280
async def get_order_book(self, symbol, limit=20, **kwargs):
278281
# override default limit to be kucoin complient

Trading/Exchange/mexc/mexc_exchange.py

Lines changed: 3 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@ class MEXC(exchanges.RestExchange):
4040

4141
REQUIRE_ORDER_FEES_FROM_TRADES = True # set True when get_order is not giving fees on closed orders and fees
4242
# text content of errors due to unhandled authentication issues
43+
# set True when create_market_buy_order_with_cost should be used to create buy market orders
44+
# (useful to predict the exact spent amount)
45+
ENABLE_SPOT_BUY_MARKET_WITH_COST = True
4346

4447
EXCHANGE_PERMISSION_ERRORS: typing.List[typing.Iterable[str]] = [
4548
# 'mexc {"code":700007,"msg":"No permission to access the endpoint."}'
@@ -95,22 +98,6 @@ async def get_all_tradable_symbols(self, active_only=True) -> set[str]:
9598
await CACHED_MEXC_API_HANDLED_SYMBOLS.update(self)
9699
return CACHED_MEXC_API_HANDLED_SYMBOLS.symbols
97100

98-
async def create_order(self, order_type: trading_enums.TraderOrderType, symbol: str, quantity: decimal.Decimal,
99-
price: decimal.Decimal = None, stop_price: decimal.Decimal = None,
100-
side: trading_enums.TradeOrderSide = None, current_price: decimal.Decimal = None,
101-
reduce_only: bool = False, params: dict = None) -> typing.Optional[dict]:
102-
if order_type is trading_enums.TraderOrderType.BUY_MARKET:
103-
# on MEXC, market orders are in quote currency (YYY in XYZ/YYY)
104-
used_price = price or current_price
105-
if not used_price:
106-
raise octobot_trading.errors.NotSupported(f"{self.get_name()} requires a price parameter to create "
107-
f"market orders as quantity is in quote currency")
108-
quantity = quantity * used_price
109-
return await super().create_order(order_type, symbol, quantity,
110-
price=price, stop_price=stop_price,
111-
side=side, current_price=current_price,
112-
reduce_only=reduce_only, params=params)
113-
114101
async def _create_specific_order(self, order_type, symbol, quantity: decimal.Decimal, price: decimal.Decimal = None,
115102
side: trading_enums.TradeOrderSide = None, current_price: decimal.Decimal = None,
116103
stop_price: decimal.Decimal = None, reduce_only: bool = False,

Trading/Exchange/phemex/phemex_exchange.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
import asyncio
1717
import decimal
1818
import typing
19-
import ccxt
2019

2120
import octobot_commons.enums as commons_enums
2221
import octobot_commons.constants as commons_constants

0 commit comments

Comments
 (0)