Merge branch 'feat/short' into fs_fix
This commit is contained in:
commit
51947ded6b
22
.github/workflows/ci.yml
vendored
22
.github/workflows/ci.yml
vendored
@ -24,10 +24,10 @@ jobs:
|
|||||||
python-version: ["3.8", "3.9", "3.10"]
|
python-version: ["3.8", "3.9", "3.10"]
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
- name: Set up Python
|
- name: Set up Python
|
||||||
uses: actions/setup-python@v2
|
uses: actions/setup-python@v3
|
||||||
with:
|
with:
|
||||||
python-version: ${{ matrix.python-version }}
|
python-version: ${{ matrix.python-version }}
|
||||||
|
|
||||||
@ -119,10 +119,10 @@ jobs:
|
|||||||
python-version: ["3.8", "3.9", "3.10"]
|
python-version: ["3.8", "3.9", "3.10"]
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
- name: Set up Python
|
- name: Set up Python
|
||||||
uses: actions/setup-python@v2
|
uses: actions/setup-python@v3
|
||||||
with:
|
with:
|
||||||
python-version: ${{ matrix.python-version }}
|
python-version: ${{ matrix.python-version }}
|
||||||
|
|
||||||
@ -211,10 +211,10 @@ jobs:
|
|||||||
python-version: ["3.8", "3.9", "3.10"]
|
python-version: ["3.8", "3.9", "3.10"]
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
- name: Set up Python
|
- name: Set up Python
|
||||||
uses: actions/setup-python@v2
|
uses: actions/setup-python@v3
|
||||||
with:
|
with:
|
||||||
python-version: ${{ matrix.python-version }}
|
python-version: ${{ matrix.python-version }}
|
||||||
|
|
||||||
@ -263,14 +263,14 @@ jobs:
|
|||||||
docs_check:
|
docs_check:
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-20.04
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
- name: Documentation syntax
|
- name: Documentation syntax
|
||||||
run: |
|
run: |
|
||||||
./tests/test_docs.sh
|
./tests/test_docs.sh
|
||||||
|
|
||||||
- name: Set up Python
|
- name: Set up Python
|
||||||
uses: actions/setup-python@v2
|
uses: actions/setup-python@v3
|
||||||
with:
|
with:
|
||||||
python-version: 3.8
|
python-version: 3.8
|
||||||
|
|
||||||
@ -326,10 +326,10 @@ jobs:
|
|||||||
if: (github.event_name == 'push' || github.event_name == 'schedule' || github.event_name == 'release') && github.repository == 'freqtrade/freqtrade'
|
if: (github.event_name == 'push' || github.event_name == 'schedule' || github.event_name == 'release') && github.repository == 'freqtrade/freqtrade'
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
- name: Set up Python
|
- name: Set up Python
|
||||||
uses: actions/setup-python@v2
|
uses: actions/setup-python@v3
|
||||||
with:
|
with:
|
||||||
python-version: 3.8
|
python-version: 3.8
|
||||||
|
|
||||||
@ -406,7 +406,7 @@ jobs:
|
|||||||
if: (github.event_name == 'push' || github.event_name == 'schedule' || github.event_name == 'release') && github.repository == 'freqtrade/freqtrade'
|
if: (github.event_name == 'push' || github.event_name == 'schedule' || github.event_name == 'release') && github.repository == 'freqtrade/freqtrade'
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
- name: Extract branch name
|
- name: Extract branch name
|
||||||
shell: bash
|
shell: bash
|
||||||
|
2
.github/workflows/docker_update_readme.yml
vendored
2
.github/workflows/docker_update_readme.yml
vendored
@ -8,7 +8,7 @@ jobs:
|
|||||||
dockerHubDescription:
|
dockerHubDescription:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v1
|
- uses: actions/checkout@v3
|
||||||
- name: Docker Hub Description
|
- name: Docker Hub Description
|
||||||
uses: peter-evans/dockerhub-description@v2.4.3
|
uses: peter-evans/dockerhub-description@v2.4.3
|
||||||
env:
|
env:
|
||||||
|
@ -58,7 +58,8 @@
|
|||||||
"forcebuy": "market",
|
"forcebuy": "market",
|
||||||
"stoploss": "market",
|
"stoploss": "market",
|
||||||
"stoploss_on_exchange": false,
|
"stoploss_on_exchange": false,
|
||||||
"stoploss_on_exchange_interval": 60
|
"stoploss_on_exchange_interval": 60,
|
||||||
|
"stoploss_on_exchange_limit_ratio": 0.99
|
||||||
},
|
},
|
||||||
"order_time_in_force": {
|
"order_time_in_force": {
|
||||||
"entry": "gtc",
|
"entry": "gtc",
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
mkdocs==1.2.3
|
mkdocs==1.2.3
|
||||||
mkdocs-material==8.2.3
|
mkdocs-material==8.2.5
|
||||||
mdx_truly_sane_lists==1.2
|
mdx_truly_sane_lists==1.2
|
||||||
pymdown-extensions==9.2
|
pymdown-extensions==9.2
|
||||||
|
@ -507,7 +507,6 @@ class FreqtradeBot(LoggingMixin):
|
|||||||
If the strategy triggers the adjustment, a new order gets issued.
|
If the strategy triggers the adjustment, a new order gets issued.
|
||||||
Once that completes, the existing trade is modified to match new data.
|
Once that completes, the existing trade is modified to match new data.
|
||||||
"""
|
"""
|
||||||
# TODO-lev: Check what changes are necessary for DCA in relation to shorts.
|
|
||||||
if self.strategy.max_entry_position_adjustment > -1:
|
if self.strategy.max_entry_position_adjustment > -1:
|
||||||
count_of_buys = trade.nr_of_successful_entries
|
count_of_buys = trade.nr_of_successful_entries
|
||||||
if count_of_buys > self.strategy.max_entry_position_adjustment:
|
if count_of_buys > self.strategy.max_entry_position_adjustment:
|
||||||
@ -1077,7 +1076,9 @@ class FreqtradeBot(LoggingMixin):
|
|||||||
:param order: Current on exchange stoploss order
|
:param order: Current on exchange stoploss order
|
||||||
:return: None
|
:return: None
|
||||||
"""
|
"""
|
||||||
if self.exchange.stoploss_adjust(trade.stop_loss, order, side=trade.exit_side):
|
stoploss_norm = self.exchange.price_to_precision(trade.pair, trade.stop_loss)
|
||||||
|
|
||||||
|
if self.exchange.stoploss_adjust(stoploss_norm, order, side=trade.exit_side):
|
||||||
# we check if the update is necessary
|
# we check if the update is necessary
|
||||||
update_beat = self.strategy.order_types.get('stoploss_on_exchange_interval', 60)
|
update_beat = self.strategy.order_types.get('stoploss_on_exchange_interval', 60)
|
||||||
if (datetime.utcnow() - trade.stoploss_last_update).total_seconds() >= update_beat:
|
if (datetime.utcnow() - trade.stoploss_last_update).total_seconds() >= update_beat:
|
||||||
|
@ -23,6 +23,7 @@ coingecko_mapping = {
|
|||||||
'eth': 'ethereum',
|
'eth': 'ethereum',
|
||||||
'bnb': 'binancecoin',
|
'bnb': 'binancecoin',
|
||||||
'sol': 'solana',
|
'sol': 'solana',
|
||||||
|
'usdt': 'tether',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -586,6 +586,9 @@ class RPC:
|
|||||||
if coin == stake_currency:
|
if coin == stake_currency:
|
||||||
rate = 1.0
|
rate = 1.0
|
||||||
est_stake = balance.total
|
est_stake = balance.total
|
||||||
|
if self._config.get('trading_mode', TradingMode.SPOT) != TradingMode.SPOT:
|
||||||
|
# in Futures, "total" includes the locked stake, and therefore all positions
|
||||||
|
est_stake = balance.free
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
pair = self._freqtrade.exchange.get_valid_pair_combination(coin, stake_currency)
|
pair = self._freqtrade.exchange.get_valid_pair_combination(coin, stake_currency)
|
||||||
@ -614,6 +617,7 @@ class RPC:
|
|||||||
symbol: str
|
symbol: str
|
||||||
position: PositionWallet
|
position: PositionWallet
|
||||||
for symbol, position in self._freqtrade.wallets.get_all_positions().items():
|
for symbol, position in self._freqtrade.wallets.get_all_positions().items():
|
||||||
|
total += position.collateral
|
||||||
|
|
||||||
currencies.append({
|
currencies.append({
|
||||||
'currency': symbol,
|
'currency': symbol,
|
||||||
|
@ -104,16 +104,16 @@ class Wallets:
|
|||||||
size = position.amount
|
size = position.amount
|
||||||
collateral = position.stake_amount
|
collateral = position.stake_amount
|
||||||
leverage = position.leverage
|
leverage = position.leverage
|
||||||
tot_in_trades -= collateral
|
tot_in_trades += collateral
|
||||||
_positions[position.pair] = PositionWallet(
|
_positions[position.pair] = PositionWallet(
|
||||||
position.pair, position=size,
|
position.pair, position=size,
|
||||||
leverage=leverage,
|
leverage=leverage,
|
||||||
collateral=collateral,
|
collateral=collateral,
|
||||||
side=position.trade_direction
|
side=position.trade_direction
|
||||||
)
|
)
|
||||||
current_stake = self.start_cap + tot_profit
|
current_stake = self.start_cap + tot_profit - tot_in_trades
|
||||||
used_stake = tot_in_trades
|
used_stake = tot_in_trades
|
||||||
total_stake = current_stake - tot_in_trades
|
total_stake = current_stake + tot_in_trades
|
||||||
|
|
||||||
_wallets[self._config['stake_currency']] = Wallet(
|
_wallets[self._config['stake_currency']] = Wallet(
|
||||||
currency=self._config['stake_currency'],
|
currency=self._config['stake_currency'],
|
||||||
|
@ -8,7 +8,7 @@ flake8==4.0.1
|
|||||||
flake8-tidy-imports==4.6.0
|
flake8-tidy-imports==4.6.0
|
||||||
mypy==0.931
|
mypy==0.931
|
||||||
pytest==7.0.1
|
pytest==7.0.1
|
||||||
pytest-asyncio==0.18.1
|
pytest-asyncio==0.18.2
|
||||||
pytest-cov==3.0.0
|
pytest-cov==3.0.0
|
||||||
pytest-mock==3.7.0
|
pytest-mock==3.7.0
|
||||||
pytest-random-order==1.0.4
|
pytest-random-order==1.0.4
|
||||||
@ -20,7 +20,7 @@ time-machine==2.6.0
|
|||||||
nbconvert==6.4.2
|
nbconvert==6.4.2
|
||||||
|
|
||||||
# mypy types
|
# mypy types
|
||||||
types-cachetools==4.2.9
|
types-cachetools==4.2.10
|
||||||
types-filelock==3.2.5
|
types-filelock==3.2.5
|
||||||
types-requests==2.27.11
|
types-requests==2.27.11
|
||||||
types-tabulate==0.8.5
|
types-tabulate==0.8.5
|
||||||
|
@ -2,11 +2,11 @@ numpy==1.22.2
|
|||||||
pandas==1.4.1
|
pandas==1.4.1
|
||||||
pandas-ta==0.3.14b
|
pandas-ta==0.3.14b
|
||||||
|
|
||||||
ccxt==1.74.63
|
ccxt==1.75.12
|
||||||
# Pin cryptography for now due to rust build errors with piwheels
|
# Pin cryptography for now due to rust build errors with piwheels
|
||||||
cryptography==36.0.1
|
cryptography==36.0.1
|
||||||
aiohttp==3.8.1
|
aiohttp==3.8.1
|
||||||
SQLAlchemy==1.4.31
|
SQLAlchemy==1.4.32
|
||||||
python-telegram-bot==13.11
|
python-telegram-bot==13.11
|
||||||
arrow==1.2.2
|
arrow==1.2.2
|
||||||
cachetools==4.2.2
|
cachetools==4.2.2
|
||||||
@ -31,7 +31,7 @@ python-rapidjson==1.6
|
|||||||
sdnotify==0.3.2
|
sdnotify==0.3.2
|
||||||
|
|
||||||
# API Server
|
# API Server
|
||||||
fastapi==0.74.1
|
fastapi==0.75.0
|
||||||
uvicorn==0.17.5
|
uvicorn==0.17.5
|
||||||
pyjwt==2.3.0
|
pyjwt==2.3.0
|
||||||
aiofiles==0.8.0
|
aiofiles==0.8.0
|
||||||
|
@ -650,8 +650,8 @@ def test_rpc_balance_handle(default_conf, mocker, tickers):
|
|||||||
rpc._fiat_converter = CryptoToFiatConverter()
|
rpc._fiat_converter = CryptoToFiatConverter()
|
||||||
|
|
||||||
result = rpc._rpc_balance(default_conf['stake_currency'], default_conf['fiat_display_currency'])
|
result = rpc._rpc_balance(default_conf['stake_currency'], default_conf['fiat_display_currency'])
|
||||||
assert prec_satoshi(result['total'], 12.309096315)
|
assert prec_satoshi(result['total'], 30.309096315)
|
||||||
assert prec_satoshi(result['value'], 184636.44472997)
|
assert prec_satoshi(result['value'], 454636.44472997)
|
||||||
assert tickers.call_count == 1
|
assert tickers.call_count == 1
|
||||||
assert tickers.call_args_list[0][1]['cached'] is True
|
assert tickers.call_args_list[0][1]['cached'] is True
|
||||||
assert 'USD' == result['symbol']
|
assert 'USD' == result['symbol']
|
||||||
@ -661,7 +661,7 @@ def test_rpc_balance_handle(default_conf, mocker, tickers):
|
|||||||
'free': 10.0,
|
'free': 10.0,
|
||||||
'balance': 12.0,
|
'balance': 12.0,
|
||||||
'used': 2.0,
|
'used': 2.0,
|
||||||
'est_stake': 12.0,
|
'est_stake': 10.0, # In futures mode, "free" is used here.
|
||||||
'stake': 'BTC',
|
'stake': 'BTC',
|
||||||
'is_position': False,
|
'is_position': False,
|
||||||
'leverage': 1.0,
|
'leverage': 1.0,
|
||||||
@ -706,7 +706,6 @@ def test_rpc_balance_handle(default_conf, mocker, tickers):
|
|||||||
'side': 'short',
|
'side': 'short',
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
assert result['total'] == 12.309096315331816
|
|
||||||
|
|
||||||
|
|
||||||
def test_rpc_start(mocker, default_conf) -> None:
|
def test_rpc_start(mocker, default_conf) -> None:
|
||||||
|
@ -1508,7 +1508,34 @@ def test_handle_stoploss_on_exchange_trailing_error(
|
|||||||
assert log_has_re(r"Could not create trailing stoploss order for pair ETH/USDT\..*", caplog)
|
assert log_has_re(r"Could not create trailing stoploss order for pair ETH/USDT\..*", caplog)
|
||||||
|
|
||||||
|
|
||||||
|
def test_stoploss_on_exchange_price_rounding(
|
||||||
|
mocker, default_conf_usdt, fee, open_trade_usdt) -> None:
|
||||||
|
patch_RPCManager(mocker)
|
||||||
|
mocker.patch.multiple(
|
||||||
|
'freqtrade.exchange.Exchange',
|
||||||
|
get_fee=fee,
|
||||||
|
)
|
||||||
|
price_mock = MagicMock(side_effect=lambda p, s: int(s))
|
||||||
|
stoploss_mock = MagicMock(return_value={'id': '13434334'})
|
||||||
|
adjust_mock = MagicMock(return_value=False)
|
||||||
|
mocker.patch.multiple(
|
||||||
|
'freqtrade.exchange.Binance',
|
||||||
|
stoploss=stoploss_mock,
|
||||||
|
stoploss_adjust=adjust_mock,
|
||||||
|
price_to_precision=price_mock,
|
||||||
|
)
|
||||||
|
freqtrade = get_patched_freqtradebot(mocker, default_conf_usdt)
|
||||||
|
open_trade_usdt.stoploss_order_id = '13434334'
|
||||||
|
open_trade_usdt.stop_loss = 222.55
|
||||||
|
|
||||||
|
freqtrade.handle_trailing_stoploss_on_exchange(open_trade_usdt, {})
|
||||||
|
assert price_mock.call_count == 1
|
||||||
|
assert adjust_mock.call_count == 1
|
||||||
|
assert adjust_mock.call_args_list[0][0][0] == 222
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("is_short", [False, True])
|
@pytest.mark.parametrize("is_short", [False, True])
|
||||||
|
@pytest.mark.usefixtures("init_persistence")
|
||||||
def test_handle_stoploss_on_exchange_custom_stop(
|
def test_handle_stoploss_on_exchange_custom_stop(
|
||||||
mocker, default_conf_usdt, fee, is_short, limit_order
|
mocker, default_conf_usdt, fee, is_short, limit_order
|
||||||
) -> None:
|
) -> None:
|
||||||
|
@ -356,3 +356,9 @@ def test_sync_wallet_futures_dry(mocker, default_conf, fee):
|
|||||||
positions['ETC/BTC'].side == 'long'
|
positions['ETC/BTC'].side == 'long'
|
||||||
positions['XRP/BTC'].side == 'long'
|
positions['XRP/BTC'].side == 'long'
|
||||||
positions['LTC/BTC'].side == 'short'
|
positions['LTC/BTC'].side == 'short'
|
||||||
|
|
||||||
|
assert freqtrade.wallets.get_starting_balance() == default_conf['dry_run_wallet']
|
||||||
|
total = freqtrade.wallets.get_total('BTC')
|
||||||
|
free = freqtrade.wallets.get_free('BTC')
|
||||||
|
used = freqtrade.wallets.get_used('BTC')
|
||||||
|
assert free + used == total
|
||||||
|
Loading…
Reference in New Issue
Block a user