Merge branch 'develop' into pr/mkavinkumar1/6545
This commit is contained in:
commit
b8c3b233dc
@ -52,10 +52,15 @@ class Binance(Exchange):
|
|||||||
|
|
||||||
ordertype = 'stop' if self.trading_mode == TradingMode.FUTURES else 'stop_loss_limit'
|
ordertype = 'stop' if self.trading_mode == TradingMode.FUTURES else 'stop_loss_limit'
|
||||||
|
|
||||||
return order['type'] == ordertype and (
|
return (
|
||||||
(side == "sell" and stop_loss > float(order['stopPrice'])) or
|
order.get('stopPrice', None) is None
|
||||||
(side == "buy" and stop_loss < float(order['stopPrice']))
|
or (
|
||||||
)
|
order['type'] == ordertype
|
||||||
|
and (
|
||||||
|
(side == "sell" and stop_loss > float(order['stopPrice'])) or
|
||||||
|
(side == "buy" and stop_loss < float(order['stopPrice']))
|
||||||
|
)
|
||||||
|
))
|
||||||
|
|
||||||
def get_tickers(self, symbols: Optional[List[str]] = None, cached: bool = False) -> Dict:
|
def get_tickers(self, symbols: Optional[List[str]] = None, cached: bool = False) -> Dict:
|
||||||
tickers = super().get_tickers(symbols=symbols, cached=cached)
|
tickers = super().get_tickers(symbols=symbols, cached=cached)
|
||||||
|
@ -2161,10 +2161,11 @@ class Exchange:
|
|||||||
except ccxt.BaseError as e:
|
except ccxt.BaseError as e:
|
||||||
raise OperationalException(e) from e
|
raise OperationalException(e) from e
|
||||||
|
|
||||||
@retrier
|
@retrier_async
|
||||||
def get_market_leverage_tiers(self, symbol) -> List[Dict]:
|
async def get_market_leverage_tiers(self, symbol: str) -> Tuple[str, List[Dict]]:
|
||||||
try:
|
try:
|
||||||
return self._api.fetch_market_leverage_tiers(symbol)
|
tier = await self._api_async.fetch_market_leverage_tiers(symbol)
|
||||||
|
return symbol, tier
|
||||||
except ccxt.DDoSProtection as e:
|
except ccxt.DDoSProtection as e:
|
||||||
raise DDosProtection(e) from e
|
raise DDosProtection(e) from e
|
||||||
except (ccxt.NetworkError, ccxt.ExchangeError) as e:
|
except (ccxt.NetworkError, ccxt.ExchangeError) as e:
|
||||||
@ -2198,8 +2199,14 @@ class Exchange:
|
|||||||
f"Initializing leverage_tiers for {len(symbols)} markets. "
|
f"Initializing leverage_tiers for {len(symbols)} markets. "
|
||||||
"This will take about a minute.")
|
"This will take about a minute.")
|
||||||
|
|
||||||
for symbol in sorted(symbols):
|
coros = [self.get_market_leverage_tiers(symbol) for symbol in sorted(symbols)]
|
||||||
tiers[symbol] = self.get_market_leverage_tiers(symbol)
|
|
||||||
|
for input_coro in chunks(coros, 100):
|
||||||
|
|
||||||
|
results = self.loop.run_until_complete(
|
||||||
|
asyncio.gather(*input_coro, return_exceptions=True))
|
||||||
|
for symbol, res in results:
|
||||||
|
tiers[symbol] = res
|
||||||
|
|
||||||
logger.info(f"Done initializing {len(symbols)} markets.")
|
logger.info(f"Done initializing {len(symbols)} markets.")
|
||||||
|
|
||||||
|
@ -114,5 +114,7 @@ class Gateio(Exchange):
|
|||||||
Verify stop_loss against stoploss-order value (limit or price)
|
Verify stop_loss against stoploss-order value (limit or price)
|
||||||
Returns True if adjustment is necessary.
|
Returns True if adjustment is necessary.
|
||||||
"""
|
"""
|
||||||
return ((side == "sell" and stop_loss > float(order['stopPrice'])) or
|
return (order.get('stopPrice', None) is None or (
|
||||||
(side == "buy" and stop_loss < float(order['stopPrice'])))
|
side == "sell" and stop_loss > float(order['stopPrice'])) or
|
||||||
|
(side == "buy" and stop_loss < float(order['stopPrice']))
|
||||||
|
)
|
||||||
|
@ -27,7 +27,13 @@ class Huobi(Exchange):
|
|||||||
Verify stop_loss against stoploss-order value (limit or price)
|
Verify stop_loss against stoploss-order value (limit or price)
|
||||||
Returns True if adjustment is necessary.
|
Returns True if adjustment is necessary.
|
||||||
"""
|
"""
|
||||||
return order['type'] == 'stop' and stop_loss > float(order['stopPrice'])
|
return (
|
||||||
|
order.get('stopPrice', None) is None
|
||||||
|
or (
|
||||||
|
order['type'] == 'stop'
|
||||||
|
and stop_loss > float(order['stopPrice'])
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
def _get_stop_params(self, ordertype: str, stop_price: float) -> Dict:
|
def _get_stop_params(self, ordertype: str, stop_price: float) -> Dict:
|
||||||
|
|
||||||
|
@ -33,7 +33,10 @@ class Kucoin(Exchange):
|
|||||||
Verify stop_loss against stoploss-order value (limit or price)
|
Verify stop_loss against stoploss-order value (limit or price)
|
||||||
Returns True if adjustment is necessary.
|
Returns True if adjustment is necessary.
|
||||||
"""
|
"""
|
||||||
return order['info'].get('stop') is not None and stop_loss > float(order['stopPrice'])
|
return (
|
||||||
|
order.get('stopPrice', None) is None
|
||||||
|
or stop_loss > float(order['stopPrice'])
|
||||||
|
)
|
||||||
|
|
||||||
def _get_stop_params(self, ordertype: str, stop_price: float) -> Dict:
|
def _get_stop_params(self, ordertype: str, stop_price: float) -> Dict:
|
||||||
|
|
||||||
|
@ -202,16 +202,18 @@ def migrate_orders_table(engine, table_back_name: str, cols_order: List):
|
|||||||
|
|
||||||
ft_fee_base = get_column_def(cols_order, 'ft_fee_base', 'null')
|
ft_fee_base = get_column_def(cols_order, 'ft_fee_base', 'null')
|
||||||
average = get_column_def(cols_order, 'average', 'null')
|
average = get_column_def(cols_order, 'average', 'null')
|
||||||
|
stop_price = get_column_def(cols_order, 'stop_price', 'null')
|
||||||
|
|
||||||
# sqlite does not support literals for booleans
|
# sqlite does not support literals for booleans
|
||||||
with engine.begin() as connection:
|
with engine.begin() as connection:
|
||||||
connection.execute(text(f"""
|
connection.execute(text(f"""
|
||||||
insert into orders (id, ft_trade_id, ft_order_side, ft_pair, ft_is_open, order_id,
|
insert into orders (id, ft_trade_id, ft_order_side, ft_pair, ft_is_open, order_id,
|
||||||
status, symbol, order_type, side, price, amount, filled, average, remaining, cost,
|
status, symbol, order_type, side, price, amount, filled, average, remaining, cost,
|
||||||
order_date, order_filled_date, order_update_date, ft_fee_base)
|
stop_price, order_date, order_filled_date, order_update_date, ft_fee_base)
|
||||||
select id, ft_trade_id, ft_order_side, ft_pair, ft_is_open, order_id,
|
select id, ft_trade_id, ft_order_side, ft_pair, ft_is_open, order_id,
|
||||||
status, symbol, order_type, side, price, amount, filled, {average} average, remaining,
|
status, symbol, order_type, side, price, amount, filled, {average} average, remaining,
|
||||||
cost, order_date, order_filled_date, order_update_date, {ft_fee_base} ft_fee_base
|
cost, {stop_price} stop_price, order_date, order_filled_date,
|
||||||
|
order_update_date, {ft_fee_base} ft_fee_base
|
||||||
from {table_back_name}
|
from {table_back_name}
|
||||||
"""))
|
"""))
|
||||||
|
|
||||||
@ -296,7 +298,7 @@ def check_migrate(engine, decl_base, previous_tables) -> None:
|
|||||||
# Check if migration necessary
|
# Check if migration necessary
|
||||||
# Migrates both trades and orders table!
|
# Migrates both trades and orders table!
|
||||||
# if ('orders' not in previous_tables
|
# if ('orders' not in previous_tables
|
||||||
# or not has_column(cols_orders, 'leverage')):
|
# or not has_column(cols_orders, 'stop_price')):
|
||||||
if not has_column(cols_trades, 'realized_profit'):
|
if not has_column(cols_trades, 'realized_profit'):
|
||||||
logger.info(f"Running database migration for trades - "
|
logger.info(f"Running database migration for trades - "
|
||||||
f"backup: {table_back_name}, {order_table_bak_name}")
|
f"backup: {table_back_name}, {order_table_bak_name}")
|
||||||
|
@ -59,6 +59,7 @@ class Order(_DECL_BASE):
|
|||||||
filled = Column(Float, nullable=True)
|
filled = Column(Float, nullable=True)
|
||||||
remaining = Column(Float, nullable=True)
|
remaining = Column(Float, nullable=True)
|
||||||
cost = Column(Float, nullable=True)
|
cost = Column(Float, nullable=True)
|
||||||
|
stop_price = Column(Float, nullable=True)
|
||||||
order_date = Column(DateTime, nullable=True, default=datetime.utcnow)
|
order_date = Column(DateTime, nullable=True, default=datetime.utcnow)
|
||||||
order_filled_date = Column(DateTime, nullable=True)
|
order_filled_date = Column(DateTime, nullable=True)
|
||||||
order_update_date = Column(DateTime, nullable=True)
|
order_update_date = Column(DateTime, nullable=True)
|
||||||
@ -109,6 +110,7 @@ class Order(_DECL_BASE):
|
|||||||
self.average = order.get('average', self.average)
|
self.average = order.get('average', self.average)
|
||||||
self.remaining = order.get('remaining', self.remaining)
|
self.remaining = order.get('remaining', self.remaining)
|
||||||
self.cost = order.get('cost', self.cost)
|
self.cost = order.get('cost', self.cost)
|
||||||
|
self.stop_price = order.get('stopPrice', self.stop_price)
|
||||||
|
|
||||||
if 'timestamp' in order and order['timestamp'] is not None:
|
if 'timestamp' in order and order['timestamp'] is not None:
|
||||||
self.order_date = datetime.fromtimestamp(order['timestamp'] / 1000, tz=timezone.utc)
|
self.order_date = datetime.fromtimestamp(order['timestamp'] / 1000, tz=timezone.utc)
|
||||||
@ -132,6 +134,7 @@ class Order(_DECL_BASE):
|
|||||||
'side': self.ft_order_side,
|
'side': self.ft_order_side,
|
||||||
'filled': self.filled,
|
'filled': self.filled,
|
||||||
'remaining': self.remaining,
|
'remaining': self.remaining,
|
||||||
|
'stopPrice': self.stop_price,
|
||||||
'datetime': self.order_date_utc.strftime('%Y-%m-%dT%H:%M:%S.%f'),
|
'datetime': self.order_date_utc.strftime('%Y-%m-%dT%H:%M:%S.%f'),
|
||||||
'timestamp': int(self.order_date_utc.timestamp() * 1000),
|
'timestamp': int(self.order_date_utc.timestamp() * 1000),
|
||||||
'status': self.status,
|
'status': self.status,
|
||||||
|
@ -78,9 +78,21 @@ def get_args(args):
|
|||||||
|
|
||||||
|
|
||||||
# Source: https://stackoverflow.com/questions/29881236/how-to-mock-asyncio-coroutines
|
# Source: https://stackoverflow.com/questions/29881236/how-to-mock-asyncio-coroutines
|
||||||
def get_mock_coro(return_value):
|
# TODO: This should be replaced with AsyncMock once support for python 3.7 is dropped.
|
||||||
|
def get_mock_coro(return_value=None, side_effect=None):
|
||||||
async def mock_coro(*args, **kwargs):
|
async def mock_coro(*args, **kwargs):
|
||||||
return return_value
|
if side_effect:
|
||||||
|
if isinstance(side_effect, list):
|
||||||
|
effect = side_effect.pop(0)
|
||||||
|
else:
|
||||||
|
effect = side_effect
|
||||||
|
if isinstance(effect, Exception):
|
||||||
|
raise effect
|
||||||
|
if callable(effect):
|
||||||
|
return effect(*args, **kwargs)
|
||||||
|
return effect
|
||||||
|
else:
|
||||||
|
return return_value
|
||||||
|
|
||||||
return Mock(wraps=mock_coro)
|
return Mock(wraps=mock_coro)
|
||||||
|
|
||||||
|
@ -123,5 +123,5 @@ def test_stoploss_adjust_kucoin(mocker, default_conf):
|
|||||||
assert exchange.stoploss_adjust(1501, order, 'sell')
|
assert exchange.stoploss_adjust(1501, order, 'sell')
|
||||||
assert not exchange.stoploss_adjust(1499, order, 'sell')
|
assert not exchange.stoploss_adjust(1499, order, 'sell')
|
||||||
# Test with invalid order case
|
# Test with invalid order case
|
||||||
order['info']['stop'] = None
|
order['stopPrice'] = None
|
||||||
assert not exchange.stoploss_adjust(1501, order, 'sell')
|
assert exchange.stoploss_adjust(1501, order, 'sell')
|
||||||
|
@ -6,7 +6,7 @@ import pytest
|
|||||||
from freqtrade.enums import MarginMode, TradingMode
|
from freqtrade.enums import MarginMode, TradingMode
|
||||||
from freqtrade.enums.candletype import CandleType
|
from freqtrade.enums.candletype import CandleType
|
||||||
from freqtrade.exchange.exchange import timeframe_to_minutes
|
from freqtrade.exchange.exchange import timeframe_to_minutes
|
||||||
from tests.conftest import get_patched_exchange
|
from tests.conftest import get_mock_coro, get_patched_exchange
|
||||||
from tests.exchange.test_exchange import ccxt_exceptionhandlers
|
from tests.exchange.test_exchange import ccxt_exceptionhandlers
|
||||||
|
|
||||||
|
|
||||||
@ -273,7 +273,7 @@ def test_load_leverage_tiers_okx(default_conf, mocker, markets):
|
|||||||
'fetchLeverageTiers': False,
|
'fetchLeverageTiers': False,
|
||||||
'fetchMarketLeverageTiers': True,
|
'fetchMarketLeverageTiers': True,
|
||||||
})
|
})
|
||||||
api_mock.fetch_market_leverage_tiers = MagicMock(side_effect=[
|
api_mock.fetch_market_leverage_tiers = get_mock_coro(side_effect=[
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
'tier': 1,
|
'tier': 1,
|
||||||
|
@ -2725,6 +2725,8 @@ def test_order_to_ccxt(limit_buy_order_open):
|
|||||||
del raw_order['fee']
|
del raw_order['fee']
|
||||||
del raw_order['datetime']
|
del raw_order['datetime']
|
||||||
del raw_order['info']
|
del raw_order['info']
|
||||||
|
assert raw_order['stopPrice'] is None
|
||||||
|
del raw_order['stopPrice']
|
||||||
del limit_buy_order_open['datetime']
|
del limit_buy_order_open['datetime']
|
||||||
assert raw_order == limit_buy_order_open
|
assert raw_order == limit_buy_order_open
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user