Merge branch 'develop' into add-spice-rack
This commit is contained in:
commit
b1e92933f4
6
.github/workflows/ci.yml
vendored
6
.github/workflows/ci.yml
vendored
@ -24,7 +24,7 @@ jobs:
|
|||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
os: [ ubuntu-18.04, ubuntu-20.04, ubuntu-22.04 ]
|
os: [ ubuntu-18.04, ubuntu-20.04, ubuntu-22.04 ]
|
||||||
python-version: ["3.8", "3.9", "3.10"]
|
python-version: ["3.8", "3.9", "3.10.6"]
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
@ -121,7 +121,7 @@ jobs:
|
|||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
os: [ macos-latest ]
|
os: [ macos-latest ]
|
||||||
python-version: ["3.8", "3.9", "3.10"]
|
python-version: ["3.8", "3.9", "3.10.6"]
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
@ -205,7 +205,7 @@ jobs:
|
|||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
os: [ windows-latest ]
|
os: [ windows-latest ]
|
||||||
python-version: ["3.8", "3.9", "3.10"]
|
python-version: ["3.8", "3.9", "3.10.6"]
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
|
@ -15,7 +15,7 @@ repos:
|
|||||||
additional_dependencies:
|
additional_dependencies:
|
||||||
- types-cachetools==5.2.1
|
- types-cachetools==5.2.1
|
||||||
- types-filelock==3.2.7
|
- types-filelock==3.2.7
|
||||||
- types-requests==2.28.9
|
- types-requests==2.28.10
|
||||||
- types-tabulate==0.8.11
|
- types-tabulate==0.8.11
|
||||||
- types-python-dateutil==2.8.19
|
- types-python-dateutil==2.8.19
|
||||||
# stages: [push]
|
# stages: [push]
|
||||||
|
@ -25,8 +25,7 @@ usage: freqtrade download-data [-h] [-v] [--logfile FILE] [-V] [-c PATH]
|
|||||||
[--include-inactive-pairs]
|
[--include-inactive-pairs]
|
||||||
[--timerange TIMERANGE] [--dl-trades]
|
[--timerange TIMERANGE] [--dl-trades]
|
||||||
[--exchange EXCHANGE]
|
[--exchange EXCHANGE]
|
||||||
[-t {1m,3m,5m,15m,30m,1h,2h,4h,6h,8h,12h,1d,3d,1w,2w,1M,1y} [{1m,3m,5m,15m,30m,1h,2h,4h,6h,8h,12h,1d,3d,1w,2w,1M,1y} ...]]
|
[-t TIMEFRAMES [TIMEFRAMES ...]] [--erase]
|
||||||
[--erase]
|
|
||||||
[--data-format-ohlcv {json,jsongz,hdf5}]
|
[--data-format-ohlcv {json,jsongz,hdf5}]
|
||||||
[--data-format-trades {json,jsongz,hdf5}]
|
[--data-format-trades {json,jsongz,hdf5}]
|
||||||
[--trading-mode {spot,margin,futures}]
|
[--trading-mode {spot,margin,futures}]
|
||||||
@ -37,7 +36,8 @@ optional arguments:
|
|||||||
-p PAIRS [PAIRS ...], --pairs PAIRS [PAIRS ...]
|
-p PAIRS [PAIRS ...], --pairs PAIRS [PAIRS ...]
|
||||||
Limit command to these pairs. Pairs are space-
|
Limit command to these pairs. Pairs are space-
|
||||||
separated.
|
separated.
|
||||||
--pairs-file FILE File containing a list of pairs to download.
|
--pairs-file FILE File containing a list of pairs. Takes precedence over
|
||||||
|
--pairs or pairs configured in the configuration.
|
||||||
--days INT Download data for given number of days.
|
--days INT Download data for given number of days.
|
||||||
--new-pairs-days INT Download data of new pairs for given number of days.
|
--new-pairs-days INT Download data of new pairs for given number of days.
|
||||||
Default: `None`.
|
Default: `None`.
|
||||||
@ -50,7 +50,7 @@ optional arguments:
|
|||||||
as --timeframes/-t.
|
as --timeframes/-t.
|
||||||
--exchange EXCHANGE Exchange name (default: `bittrex`). Only valid if no
|
--exchange EXCHANGE Exchange name (default: `bittrex`). Only valid if no
|
||||||
config is provided.
|
config is provided.
|
||||||
-t {1m,3m,5m,15m,30m,1h,2h,4h,6h,8h,12h,1d,3d,1w,2w,1M,1y} [{1m,3m,5m,15m,30m,1h,2h,4h,6h,8h,12h,1d,3d,1w,2w,1M,1y} ...], --timeframes {1m,3m,5m,15m,30m,1h,2h,4h,6h,8h,12h,1d,3d,1w,2w,1M,1y} [{1m,3m,5m,15m,30m,1h,2h,4h,6h,8h,12h,1d,3d,1w,2w,1M,1y} ...]
|
-t TIMEFRAMES [TIMEFRAMES ...], --timeframes TIMEFRAMES [TIMEFRAMES ...]
|
||||||
Specify which tickers to download. Space-separated
|
Specify which tickers to download. Space-separated
|
||||||
list. Default: `1m 5m`.
|
list. Default: `1m 5m`.
|
||||||
--erase Clean all existing data for the selected
|
--erase Clean all existing data for the selected
|
||||||
@ -61,7 +61,7 @@ optional arguments:
|
|||||||
--data-format-trades {json,jsongz,hdf5}
|
--data-format-trades {json,jsongz,hdf5}
|
||||||
Storage format for downloaded trades data. (default:
|
Storage format for downloaded trades data. (default:
|
||||||
`jsongz`).
|
`jsongz`).
|
||||||
--trading-mode {spot,margin,futures}
|
--trading-mode {spot,margin,futures}, --tradingmode {spot,margin,futures}
|
||||||
Select Trading mode
|
Select Trading mode
|
||||||
--prepend Allow data prepending. (Data-appending is disabled)
|
--prepend Allow data prepending. (Data-appending is disabled)
|
||||||
|
|
||||||
|
@ -57,7 +57,8 @@ This configuration enables kraken, as well as rate-limiting to avoid bans from t
|
|||||||
Binance supports [time_in_force](configuration.md#understand-order_time_in_force).
|
Binance supports [time_in_force](configuration.md#understand-order_time_in_force).
|
||||||
|
|
||||||
!!! Tip "Stoploss on Exchange"
|
!!! Tip "Stoploss on Exchange"
|
||||||
Binance supports `stoploss_on_exchange` and uses `stop-loss-limit` orders. It provides great advantages, so we recommend to benefit from it by enabling stoploss on exchange..
|
Binance supports `stoploss_on_exchange` and uses `stop-loss-limit` orders. It provides great advantages, so we recommend to benefit from it by enabling stoploss on exchange.
|
||||||
|
On futures, Binance supports both `stop-limit` as well as `stop-market` orders. You can use either `"limit"` or `"market"` in the `order_types.stoploss` configuration setting to decide which type to use.
|
||||||
|
|
||||||
### Binance Blacklist
|
### Binance Blacklist
|
||||||
|
|
||||||
|
@ -190,19 +190,6 @@ The FreqAI strategy requires the user to include the following lines of code in
|
|||||||
# passed to any single indicator)
|
# passed to any single indicator)
|
||||||
startup_candle_count: int = 20
|
startup_candle_count: int = 20
|
||||||
|
|
||||||
def informative_pairs(self):
|
|
||||||
whitelist_pairs = self.dp.current_whitelist()
|
|
||||||
corr_pairs = self.config["freqai"]["feature_parameters"]["include_corr_pairlist"]
|
|
||||||
informative_pairs = []
|
|
||||||
for tf in self.config["freqai"]["feature_parameters"]["include_timeframes"]:
|
|
||||||
for pair in whitelist_pairs:
|
|
||||||
informative_pairs.append((pair, tf))
|
|
||||||
for pair in corr_pairs:
|
|
||||||
if pair in whitelist_pairs:
|
|
||||||
continue # avoid duplication
|
|
||||||
informative_pairs.append((pair, tf))
|
|
||||||
return informative_pairs
|
|
||||||
|
|
||||||
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||||
|
|
||||||
# the model will return all labels created by user in `populate_any_indicators`
|
# the model will return all labels created by user in `populate_any_indicators`
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
markdown==3.3.7
|
markdown==3.3.7
|
||||||
mkdocs==1.3.1
|
mkdocs==1.3.1
|
||||||
mkdocs-material==8.4.2
|
mkdocs-material==8.4.3
|
||||||
mdx_truly_sane_lists==1.3
|
mdx_truly_sane_lists==1.3
|
||||||
pymdown-extensions==9.5
|
pymdown-extensions==9.5
|
||||||
jinja2==3.1.2
|
jinja2==3.1.2
|
||||||
|
@ -264,7 +264,8 @@ def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFram
|
|||||||
### Exit signal rules
|
### Exit signal rules
|
||||||
|
|
||||||
Edit the method `populate_exit_trend()` into your strategy file to update your exit strategy.
|
Edit the method `populate_exit_trend()` into your strategy file to update your exit strategy.
|
||||||
Please note that the exit-signal is only used if `use_exit_signal` is set to true in the configuration.
|
The exit-signal is only used for exits if `use_exit_signal` is set to true in the configuration.
|
||||||
|
`use_exit_signal` will not influence [signal collision rules](#colliding-signals) - which will still apply and can prevent entries.
|
||||||
|
|
||||||
It's important to always return the dataframe without removing/modifying the columns `"open", "high", "low", "close", "volume"`, otherwise these fields would contain something unexpected.
|
It's important to always return the dataframe without removing/modifying the columns `"open", "high", "low", "close", "volume"`, otherwise these fields would contain something unexpected.
|
||||||
|
|
||||||
|
@ -525,12 +525,14 @@ Requires a configuration with specified `pairlists` attribute.
|
|||||||
Can be used to generate static pairlists to be used during backtesting / hyperopt.
|
Can be used to generate static pairlists to be used during backtesting / hyperopt.
|
||||||
|
|
||||||
```
|
```
|
||||||
usage: freqtrade test-pairlist [-h] [-v] [-c PATH]
|
usage: freqtrade test-pairlist [-h] [--userdir PATH] [-v] [-c PATH]
|
||||||
[--quote QUOTE_CURRENCY [QUOTE_CURRENCY ...]]
|
[--quote QUOTE_CURRENCY [QUOTE_CURRENCY ...]]
|
||||||
[-1] [--print-json] [--exchange EXCHANGE]
|
[-1] [--print-json] [--exchange EXCHANGE]
|
||||||
|
|
||||||
optional arguments:
|
optional arguments:
|
||||||
-h, --help show this help message and exit
|
-h, --help show this help message and exit
|
||||||
|
--userdir PATH, --user-data-dir PATH
|
||||||
|
Path to userdata directory.
|
||||||
-v, --verbose Verbose mode (-vv for more, -vvv to get all messages).
|
-v, --verbose Verbose mode (-vv for more, -vvv to get all messages).
|
||||||
-c PATH, --config PATH
|
-c PATH, --config PATH
|
||||||
Specify configuration file (default:
|
Specify configuration file (default:
|
||||||
|
@ -53,8 +53,8 @@ ARGS_LIST_PAIRS = ["exchange", "print_list", "list_pairs_print_json", "print_one
|
|||||||
"print_csv", "base_currencies", "quote_currencies", "list_pairs_all",
|
"print_csv", "base_currencies", "quote_currencies", "list_pairs_all",
|
||||||
"trading_mode"]
|
"trading_mode"]
|
||||||
|
|
||||||
ARGS_TEST_PAIRLIST = ["verbosity", "config", "quote_currencies", "print_one_column",
|
ARGS_TEST_PAIRLIST = ["user_data_dir", "verbosity", "config", "quote_currencies",
|
||||||
"list_pairs_print_json", "exchange"]
|
"print_one_column", "list_pairs_print_json", "exchange"]
|
||||||
|
|
||||||
ARGS_CREATE_USERDIR = ["user_data_dir", "reset"]
|
ARGS_CREATE_USERDIR = ["user_data_dir", "reset"]
|
||||||
|
|
||||||
|
@ -393,7 +393,8 @@ AVAILABLE_CLI_OPTIONS = {
|
|||||||
# Download data
|
# Download data
|
||||||
"pairs_file": Arg(
|
"pairs_file": Arg(
|
||||||
'--pairs-file',
|
'--pairs-file',
|
||||||
help='File containing a list of pairs to download.',
|
help='File containing a list of pairs. '
|
||||||
|
'Takes precedence over --pairs or pairs configured in the configuration.',
|
||||||
metavar='FILE',
|
metavar='FILE',
|
||||||
),
|
),
|
||||||
"days": Arg(
|
"days": Arg(
|
||||||
|
@ -86,7 +86,7 @@ class DataProvider:
|
|||||||
"""
|
"""
|
||||||
_candle_type = CandleType.from_string(
|
_candle_type = CandleType.from_string(
|
||||||
candle_type) if candle_type != '' else self._config['candle_type_def']
|
candle_type) if candle_type != '' else self._config['candle_type_def']
|
||||||
saved_pair = (pair, str(timeframe), _candle_type)
|
saved_pair: PairWithTimeframe = (pair, str(timeframe), _candle_type)
|
||||||
if saved_pair not in self.__cached_pairs_backtesting:
|
if saved_pair not in self.__cached_pairs_backtesting:
|
||||||
timerange = TimeRange.parse_timerange(None if self._config.get(
|
timerange = TimeRange.parse_timerange(None if self._config.get(
|
||||||
'timerange') is None else str(self._config.get('timerange')))
|
'timerange') is None else str(self._config.get('timerange')))
|
||||||
@ -196,7 +196,9 @@ class DataProvider:
|
|||||||
Clear pair dataframe cache.
|
Clear pair dataframe cache.
|
||||||
"""
|
"""
|
||||||
self.__cached_pairs = {}
|
self.__cached_pairs = {}
|
||||||
self.__cached_pairs_backtesting = {}
|
# Don't reset backtesting pairs -
|
||||||
|
# otherwise they're reloaded each time during hyperopt due to with analyze_per_epoch
|
||||||
|
# self.__cached_pairs_backtesting = {}
|
||||||
self.__slice_index = 0
|
self.__slice_index = 0
|
||||||
|
|
||||||
# Exchange functions
|
# Exchange functions
|
||||||
|
@ -31,7 +31,7 @@ class Binance(Exchange):
|
|||||||
"ccxt_futures_name": "future"
|
"ccxt_futures_name": "future"
|
||||||
}
|
}
|
||||||
_ft_has_futures: Dict = {
|
_ft_has_futures: Dict = {
|
||||||
"stoploss_order_types": {"limit": "stop"},
|
"stoploss_order_types": {"limit": "limit", "market": "market"},
|
||||||
"tickers_have_price": False,
|
"tickers_have_price": False,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -48,13 +48,12 @@ class Binance(Exchange):
|
|||||||
Returns True if adjustment is necessary.
|
Returns True if adjustment is necessary.
|
||||||
:param side: "buy" or "sell"
|
:param side: "buy" or "sell"
|
||||||
"""
|
"""
|
||||||
|
order_types = ('stop_loss_limit', 'stop', 'stop_market')
|
||||||
ordertype = 'stop' if self.trading_mode == TradingMode.FUTURES else 'stop_loss_limit'
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
order.get('stopPrice', None) is None
|
order.get('stopPrice', None) is None
|
||||||
or (
|
or (
|
||||||
order['type'] == ordertype
|
order['type'] in order_types
|
||||||
and (
|
and (
|
||||||
(side == "sell" and stop_loss > float(order['stopPrice'])) or
|
(side == "sell" and stop_loss > float(order['stopPrice'])) or
|
||||||
(side == "buy" and stop_loss < float(order['stopPrice']))
|
(side == "buy" and stop_loss < float(order['stopPrice']))
|
||||||
|
@ -81,6 +81,104 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"1000LUNC/USDT": [
|
||||||
|
{
|
||||||
|
"tier": 1.0,
|
||||||
|
"currency": "USDT",
|
||||||
|
"minNotional": 0.0,
|
||||||
|
"maxNotional": 5000.0,
|
||||||
|
"maintenanceMarginRate": 0.01,
|
||||||
|
"maxLeverage": 25.0,
|
||||||
|
"info": {
|
||||||
|
"bracket": "1",
|
||||||
|
"initialLeverage": "25",
|
||||||
|
"notionalCap": "5000",
|
||||||
|
"notionalFloor": "0",
|
||||||
|
"maintMarginRatio": "0.01",
|
||||||
|
"cum": "0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tier": 2.0,
|
||||||
|
"currency": "USDT",
|
||||||
|
"minNotional": 5000.0,
|
||||||
|
"maxNotional": 25000.0,
|
||||||
|
"maintenanceMarginRate": 0.025,
|
||||||
|
"maxLeverage": 20.0,
|
||||||
|
"info": {
|
||||||
|
"bracket": "2",
|
||||||
|
"initialLeverage": "20",
|
||||||
|
"notionalCap": "25000",
|
||||||
|
"notionalFloor": "5000",
|
||||||
|
"maintMarginRatio": "0.025",
|
||||||
|
"cum": "75.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tier": 3.0,
|
||||||
|
"currency": "USDT",
|
||||||
|
"minNotional": 25000.0,
|
||||||
|
"maxNotional": 100000.0,
|
||||||
|
"maintenanceMarginRate": 0.05,
|
||||||
|
"maxLeverage": 10.0,
|
||||||
|
"info": {
|
||||||
|
"bracket": "3",
|
||||||
|
"initialLeverage": "10",
|
||||||
|
"notionalCap": "100000",
|
||||||
|
"notionalFloor": "25000",
|
||||||
|
"maintMarginRatio": "0.05",
|
||||||
|
"cum": "700.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tier": 4.0,
|
||||||
|
"currency": "USDT",
|
||||||
|
"minNotional": 100000.0,
|
||||||
|
"maxNotional": 250000.0,
|
||||||
|
"maintenanceMarginRate": 0.1,
|
||||||
|
"maxLeverage": 5.0,
|
||||||
|
"info": {
|
||||||
|
"bracket": "4",
|
||||||
|
"initialLeverage": "5",
|
||||||
|
"notionalCap": "250000",
|
||||||
|
"notionalFloor": "100000",
|
||||||
|
"maintMarginRatio": "0.1",
|
||||||
|
"cum": "5700.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tier": 5.0,
|
||||||
|
"currency": "USDT",
|
||||||
|
"minNotional": 250000.0,
|
||||||
|
"maxNotional": 1000000.0,
|
||||||
|
"maintenanceMarginRate": 0.125,
|
||||||
|
"maxLeverage": 2.0,
|
||||||
|
"info": {
|
||||||
|
"bracket": "5",
|
||||||
|
"initialLeverage": "2",
|
||||||
|
"notionalCap": "1000000",
|
||||||
|
"notionalFloor": "250000",
|
||||||
|
"maintMarginRatio": "0.125",
|
||||||
|
"cum": "11950.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tier": 6.0,
|
||||||
|
"currency": "USDT",
|
||||||
|
"minNotional": 1000000.0,
|
||||||
|
"maxNotional": 5000000.0,
|
||||||
|
"maintenanceMarginRate": 0.5,
|
||||||
|
"maxLeverage": 1.0,
|
||||||
|
"info": {
|
||||||
|
"bracket": "6",
|
||||||
|
"initialLeverage": "1",
|
||||||
|
"notionalCap": "5000000",
|
||||||
|
"notionalFloor": "1000000",
|
||||||
|
"maintMarginRatio": "0.5",
|
||||||
|
"cum": "386950.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
"1000SHIB/BUSD": [
|
"1000SHIB/BUSD": [
|
||||||
{
|
{
|
||||||
"tier": 1.0,
|
"tier": 1.0,
|
||||||
@ -1109,6 +1207,88 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"AMB/BUSD": [
|
||||||
|
{
|
||||||
|
"tier": 1.0,
|
||||||
|
"currency": "BUSD",
|
||||||
|
"minNotional": 0.0,
|
||||||
|
"maxNotional": 25000.0,
|
||||||
|
"maintenanceMarginRate": 0.025,
|
||||||
|
"maxLeverage": 20.0,
|
||||||
|
"info": {
|
||||||
|
"bracket": "1",
|
||||||
|
"initialLeverage": "20",
|
||||||
|
"notionalCap": "25000",
|
||||||
|
"notionalFloor": "0",
|
||||||
|
"maintMarginRatio": "0.025",
|
||||||
|
"cum": "0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tier": 2.0,
|
||||||
|
"currency": "BUSD",
|
||||||
|
"minNotional": 25000.0,
|
||||||
|
"maxNotional": 100000.0,
|
||||||
|
"maintenanceMarginRate": 0.05,
|
||||||
|
"maxLeverage": 10.0,
|
||||||
|
"info": {
|
||||||
|
"bracket": "2",
|
||||||
|
"initialLeverage": "10",
|
||||||
|
"notionalCap": "100000",
|
||||||
|
"notionalFloor": "25000",
|
||||||
|
"maintMarginRatio": "0.05",
|
||||||
|
"cum": "625.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tier": 3.0,
|
||||||
|
"currency": "BUSD",
|
||||||
|
"minNotional": 100000.0,
|
||||||
|
"maxNotional": 250000.0,
|
||||||
|
"maintenanceMarginRate": 0.1,
|
||||||
|
"maxLeverage": 5.0,
|
||||||
|
"info": {
|
||||||
|
"bracket": "3",
|
||||||
|
"initialLeverage": "5",
|
||||||
|
"notionalCap": "250000",
|
||||||
|
"notionalFloor": "100000",
|
||||||
|
"maintMarginRatio": "0.1",
|
||||||
|
"cum": "5625.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tier": 4.0,
|
||||||
|
"currency": "BUSD",
|
||||||
|
"minNotional": 250000.0,
|
||||||
|
"maxNotional": 1000000.0,
|
||||||
|
"maintenanceMarginRate": 0.125,
|
||||||
|
"maxLeverage": 2.0,
|
||||||
|
"info": {
|
||||||
|
"bracket": "4",
|
||||||
|
"initialLeverage": "2",
|
||||||
|
"notionalCap": "1000000",
|
||||||
|
"notionalFloor": "250000",
|
||||||
|
"maintMarginRatio": "0.125",
|
||||||
|
"cum": "11875.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tier": 5.0,
|
||||||
|
"currency": "BUSD",
|
||||||
|
"minNotional": 1000000.0,
|
||||||
|
"maxNotional": 5000000.0,
|
||||||
|
"maintenanceMarginRate": 0.5,
|
||||||
|
"maxLeverage": 1.0,
|
||||||
|
"info": {
|
||||||
|
"bracket": "5",
|
||||||
|
"initialLeverage": "1",
|
||||||
|
"notionalCap": "5000000",
|
||||||
|
"notionalFloor": "1000000",
|
||||||
|
"maintMarginRatio": "0.5",
|
||||||
|
"cum": "386875.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
"ANC/BUSD": [
|
"ANC/BUSD": [
|
||||||
{
|
{
|
||||||
"tier": 1.0,
|
"tier": 1.0,
|
||||||
@ -3300,13 +3480,13 @@
|
|||||||
"tier": 6.0,
|
"tier": 6.0,
|
||||||
"currency": "USDT",
|
"currency": "USDT",
|
||||||
"minNotional": 1000000.0,
|
"minNotional": 1000000.0,
|
||||||
"maxNotional": 30000000.0,
|
"maxNotional": 5000000.0,
|
||||||
"maintenanceMarginRate": 0.5,
|
"maintenanceMarginRate": 0.5,
|
||||||
"maxLeverage": 1.0,
|
"maxLeverage": 1.0,
|
||||||
"info": {
|
"info": {
|
||||||
"bracket": "6",
|
"bracket": "6",
|
||||||
"initialLeverage": "1",
|
"initialLeverage": "1",
|
||||||
"notionalCap": "30000000",
|
"notionalCap": "5000000",
|
||||||
"notionalFloor": "1000000",
|
"notionalFloor": "1000000",
|
||||||
"maintMarginRatio": "0.5",
|
"maintMarginRatio": "0.5",
|
||||||
"cum": "386950.0"
|
"cum": "386950.0"
|
||||||
@ -4880,13 +5060,13 @@
|
|||||||
"tier": 6.0,
|
"tier": 6.0,
|
||||||
"currency": "USDT",
|
"currency": "USDT",
|
||||||
"minNotional": 1000000.0,
|
"minNotional": 1000000.0,
|
||||||
"maxNotional": 30000000.0,
|
"maxNotional": 5000000.0,
|
||||||
"maintenanceMarginRate": 0.5,
|
"maintenanceMarginRate": 0.5,
|
||||||
"maxLeverage": 1.0,
|
"maxLeverage": 1.0,
|
||||||
"info": {
|
"info": {
|
||||||
"bracket": "6",
|
"bracket": "6",
|
||||||
"initialLeverage": "1",
|
"initialLeverage": "1",
|
||||||
"notionalCap": "30000000",
|
"notionalCap": "5000000",
|
||||||
"notionalFloor": "1000000",
|
"notionalFloor": "1000000",
|
||||||
"maintMarginRatio": "0.5",
|
"maintMarginRatio": "0.5",
|
||||||
"cum": "386940.0"
|
"cum": "386940.0"
|
||||||
@ -8333,6 +8513,104 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"FOOTBALL/USDT": [
|
||||||
|
{
|
||||||
|
"tier": 1.0,
|
||||||
|
"currency": "USDT",
|
||||||
|
"minNotional": 0.0,
|
||||||
|
"maxNotional": 5000.0,
|
||||||
|
"maintenanceMarginRate": 0.01,
|
||||||
|
"maxLeverage": 25.0,
|
||||||
|
"info": {
|
||||||
|
"bracket": "1",
|
||||||
|
"initialLeverage": "25",
|
||||||
|
"notionalCap": "5000",
|
||||||
|
"notionalFloor": "0",
|
||||||
|
"maintMarginRatio": "0.01",
|
||||||
|
"cum": "0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tier": 2.0,
|
||||||
|
"currency": "USDT",
|
||||||
|
"minNotional": 5000.0,
|
||||||
|
"maxNotional": 25000.0,
|
||||||
|
"maintenanceMarginRate": 0.025,
|
||||||
|
"maxLeverage": 20.0,
|
||||||
|
"info": {
|
||||||
|
"bracket": "2",
|
||||||
|
"initialLeverage": "20",
|
||||||
|
"notionalCap": "25000",
|
||||||
|
"notionalFloor": "5000",
|
||||||
|
"maintMarginRatio": "0.025",
|
||||||
|
"cum": "75.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tier": 3.0,
|
||||||
|
"currency": "USDT",
|
||||||
|
"minNotional": 25000.0,
|
||||||
|
"maxNotional": 100000.0,
|
||||||
|
"maintenanceMarginRate": 0.05,
|
||||||
|
"maxLeverage": 10.0,
|
||||||
|
"info": {
|
||||||
|
"bracket": "3",
|
||||||
|
"initialLeverage": "10",
|
||||||
|
"notionalCap": "100000",
|
||||||
|
"notionalFloor": "25000",
|
||||||
|
"maintMarginRatio": "0.05",
|
||||||
|
"cum": "700.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tier": 4.0,
|
||||||
|
"currency": "USDT",
|
||||||
|
"minNotional": 100000.0,
|
||||||
|
"maxNotional": 250000.0,
|
||||||
|
"maintenanceMarginRate": 0.1,
|
||||||
|
"maxLeverage": 5.0,
|
||||||
|
"info": {
|
||||||
|
"bracket": "4",
|
||||||
|
"initialLeverage": "5",
|
||||||
|
"notionalCap": "250000",
|
||||||
|
"notionalFloor": "100000",
|
||||||
|
"maintMarginRatio": "0.1",
|
||||||
|
"cum": "5700.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tier": 5.0,
|
||||||
|
"currency": "USDT",
|
||||||
|
"minNotional": 250000.0,
|
||||||
|
"maxNotional": 1000000.0,
|
||||||
|
"maintenanceMarginRate": 0.125,
|
||||||
|
"maxLeverage": 2.0,
|
||||||
|
"info": {
|
||||||
|
"bracket": "5",
|
||||||
|
"initialLeverage": "2",
|
||||||
|
"notionalCap": "1000000",
|
||||||
|
"notionalFloor": "250000",
|
||||||
|
"maintMarginRatio": "0.125",
|
||||||
|
"cum": "11950.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tier": 6.0,
|
||||||
|
"currency": "USDT",
|
||||||
|
"minNotional": 1000000.0,
|
||||||
|
"maxNotional": 5000000.0,
|
||||||
|
"maintenanceMarginRate": 0.5,
|
||||||
|
"maxLeverage": 1.0,
|
||||||
|
"info": {
|
||||||
|
"bracket": "6",
|
||||||
|
"initialLeverage": "1",
|
||||||
|
"notionalCap": "5000000",
|
||||||
|
"notionalFloor": "1000000",
|
||||||
|
"maintMarginRatio": "0.5",
|
||||||
|
"cum": "386950.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
"FTM/BUSD": [
|
"FTM/BUSD": [
|
||||||
{
|
{
|
||||||
"tier": 1.0,
|
"tier": 1.0,
|
||||||
@ -12123,6 +12401,104 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"LUNA2/USDT": [
|
||||||
|
{
|
||||||
|
"tier": 1.0,
|
||||||
|
"currency": "USDT",
|
||||||
|
"minNotional": 0.0,
|
||||||
|
"maxNotional": 5000.0,
|
||||||
|
"maintenanceMarginRate": 0.015,
|
||||||
|
"maxLeverage": 25.0,
|
||||||
|
"info": {
|
||||||
|
"bracket": "1",
|
||||||
|
"initialLeverage": "25",
|
||||||
|
"notionalCap": "5000",
|
||||||
|
"notionalFloor": "0",
|
||||||
|
"maintMarginRatio": "0.015",
|
||||||
|
"cum": "0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tier": 2.0,
|
||||||
|
"currency": "USDT",
|
||||||
|
"minNotional": 5000.0,
|
||||||
|
"maxNotional": 25000.0,
|
||||||
|
"maintenanceMarginRate": 0.025,
|
||||||
|
"maxLeverage": 20.0,
|
||||||
|
"info": {
|
||||||
|
"bracket": "2",
|
||||||
|
"initialLeverage": "20",
|
||||||
|
"notionalCap": "25000",
|
||||||
|
"notionalFloor": "5000",
|
||||||
|
"maintMarginRatio": "0.025",
|
||||||
|
"cum": "50.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tier": 3.0,
|
||||||
|
"currency": "USDT",
|
||||||
|
"minNotional": 25000.0,
|
||||||
|
"maxNotional": 100000.0,
|
||||||
|
"maintenanceMarginRate": 0.05,
|
||||||
|
"maxLeverage": 10.0,
|
||||||
|
"info": {
|
||||||
|
"bracket": "3",
|
||||||
|
"initialLeverage": "10",
|
||||||
|
"notionalCap": "100000",
|
||||||
|
"notionalFloor": "25000",
|
||||||
|
"maintMarginRatio": "0.05",
|
||||||
|
"cum": "675.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tier": 4.0,
|
||||||
|
"currency": "USDT",
|
||||||
|
"minNotional": 100000.0,
|
||||||
|
"maxNotional": 250000.0,
|
||||||
|
"maintenanceMarginRate": 0.1,
|
||||||
|
"maxLeverage": 5.0,
|
||||||
|
"info": {
|
||||||
|
"bracket": "4",
|
||||||
|
"initialLeverage": "5",
|
||||||
|
"notionalCap": "250000",
|
||||||
|
"notionalFloor": "100000",
|
||||||
|
"maintMarginRatio": "0.1",
|
||||||
|
"cum": "5675.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tier": 5.0,
|
||||||
|
"currency": "USDT",
|
||||||
|
"minNotional": 250000.0,
|
||||||
|
"maxNotional": 1000000.0,
|
||||||
|
"maintenanceMarginRate": 0.125,
|
||||||
|
"maxLeverage": 2.0,
|
||||||
|
"info": {
|
||||||
|
"bracket": "5",
|
||||||
|
"initialLeverage": "2",
|
||||||
|
"notionalCap": "1000000",
|
||||||
|
"notionalFloor": "250000",
|
||||||
|
"maintMarginRatio": "0.125",
|
||||||
|
"cum": "11925.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tier": 6.0,
|
||||||
|
"currency": "USDT",
|
||||||
|
"minNotional": 1000000.0,
|
||||||
|
"maxNotional": 5000000.0,
|
||||||
|
"maintenanceMarginRate": 0.5,
|
||||||
|
"maxLeverage": 1.0,
|
||||||
|
"info": {
|
||||||
|
"bracket": "6",
|
||||||
|
"initialLeverage": "1",
|
||||||
|
"notionalCap": "5000000",
|
||||||
|
"notionalFloor": "1000000",
|
||||||
|
"maintMarginRatio": "0.5",
|
||||||
|
"cum": "386925.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
"MANA/USDT": [
|
"MANA/USDT": [
|
||||||
{
|
{
|
||||||
"tier": 1.0,
|
"tier": 1.0,
|
||||||
@ -13028,10 +13404,10 @@
|
|||||||
"minNotional": 0.0,
|
"minNotional": 0.0,
|
||||||
"maxNotional": 5000.0,
|
"maxNotional": 5000.0,
|
||||||
"maintenanceMarginRate": 0.01,
|
"maintenanceMarginRate": 0.01,
|
||||||
"maxLeverage": 50.0,
|
"maxLeverage": 25.0,
|
||||||
"info": {
|
"info": {
|
||||||
"bracket": "1",
|
"bracket": "1",
|
||||||
"initialLeverage": "50",
|
"initialLeverage": "25",
|
||||||
"notionalCap": "5000",
|
"notionalCap": "5000",
|
||||||
"notionalFloor": "0",
|
"notionalFloor": "0",
|
||||||
"maintMarginRatio": "0.01",
|
"maintMarginRatio": "0.01",
|
||||||
@ -13805,6 +14181,88 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"PHB/BUSD": [
|
||||||
|
{
|
||||||
|
"tier": 1.0,
|
||||||
|
"currency": "BUSD",
|
||||||
|
"minNotional": 0.0,
|
||||||
|
"maxNotional": 25000.0,
|
||||||
|
"maintenanceMarginRate": 0.025,
|
||||||
|
"maxLeverage": 20.0,
|
||||||
|
"info": {
|
||||||
|
"bracket": "1",
|
||||||
|
"initialLeverage": "20",
|
||||||
|
"notionalCap": "25000",
|
||||||
|
"notionalFloor": "0",
|
||||||
|
"maintMarginRatio": "0.025",
|
||||||
|
"cum": "0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tier": 2.0,
|
||||||
|
"currency": "BUSD",
|
||||||
|
"minNotional": 25000.0,
|
||||||
|
"maxNotional": 100000.0,
|
||||||
|
"maintenanceMarginRate": 0.05,
|
||||||
|
"maxLeverage": 10.0,
|
||||||
|
"info": {
|
||||||
|
"bracket": "2",
|
||||||
|
"initialLeverage": "10",
|
||||||
|
"notionalCap": "100000",
|
||||||
|
"notionalFloor": "25000",
|
||||||
|
"maintMarginRatio": "0.05",
|
||||||
|
"cum": "625.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tier": 3.0,
|
||||||
|
"currency": "BUSD",
|
||||||
|
"minNotional": 100000.0,
|
||||||
|
"maxNotional": 250000.0,
|
||||||
|
"maintenanceMarginRate": 0.1,
|
||||||
|
"maxLeverage": 5.0,
|
||||||
|
"info": {
|
||||||
|
"bracket": "3",
|
||||||
|
"initialLeverage": "5",
|
||||||
|
"notionalCap": "250000",
|
||||||
|
"notionalFloor": "100000",
|
||||||
|
"maintMarginRatio": "0.1",
|
||||||
|
"cum": "5625.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tier": 4.0,
|
||||||
|
"currency": "BUSD",
|
||||||
|
"minNotional": 250000.0,
|
||||||
|
"maxNotional": 1000000.0,
|
||||||
|
"maintenanceMarginRate": 0.125,
|
||||||
|
"maxLeverage": 2.0,
|
||||||
|
"info": {
|
||||||
|
"bracket": "4",
|
||||||
|
"initialLeverage": "2",
|
||||||
|
"notionalCap": "1000000",
|
||||||
|
"notionalFloor": "250000",
|
||||||
|
"maintMarginRatio": "0.125",
|
||||||
|
"cum": "11875.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tier": 5.0,
|
||||||
|
"currency": "BUSD",
|
||||||
|
"minNotional": 1000000.0,
|
||||||
|
"maxNotional": 5000000.0,
|
||||||
|
"maintenanceMarginRate": 0.5,
|
||||||
|
"maxLeverage": 1.0,
|
||||||
|
"info": {
|
||||||
|
"bracket": "5",
|
||||||
|
"initialLeverage": "1",
|
||||||
|
"notionalCap": "5000000",
|
||||||
|
"notionalFloor": "1000000",
|
||||||
|
"maintMarginRatio": "0.5",
|
||||||
|
"cum": "386875.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
"QTUM/USDT": [
|
"QTUM/USDT": [
|
||||||
{
|
{
|
||||||
"tier": 1.0,
|
"tier": 1.0,
|
||||||
@ -14008,10 +14466,10 @@
|
|||||||
"minNotional": 0.0,
|
"minNotional": 0.0,
|
||||||
"maxNotional": 5000.0,
|
"maxNotional": 5000.0,
|
||||||
"maintenanceMarginRate": 0.01,
|
"maintenanceMarginRate": 0.01,
|
||||||
"maxLeverage": 50.0,
|
"maxLeverage": 25.0,
|
||||||
"info": {
|
"info": {
|
||||||
"bracket": "1",
|
"bracket": "1",
|
||||||
"initialLeverage": "50",
|
"initialLeverage": "25",
|
||||||
"notionalCap": "5000",
|
"notionalCap": "5000",
|
||||||
"notionalFloor": "0",
|
"notionalFloor": "0",
|
||||||
"maintMarginRatio": "0.01",
|
"maintMarginRatio": "0.01",
|
||||||
@ -14478,13 +14936,13 @@
|
|||||||
"tier": 6.0,
|
"tier": 6.0,
|
||||||
"currency": "USDT",
|
"currency": "USDT",
|
||||||
"minNotional": 1000000.0,
|
"minNotional": 1000000.0,
|
||||||
"maxNotional": 30000000.0,
|
"maxNotional": 5000000.0,
|
||||||
"maintenanceMarginRate": 0.5,
|
"maintenanceMarginRate": 0.5,
|
||||||
"maxLeverage": 1.0,
|
"maxLeverage": 1.0,
|
||||||
"info": {
|
"info": {
|
||||||
"bracket": "6",
|
"bracket": "6",
|
||||||
"initialLeverage": "1",
|
"initialLeverage": "1",
|
||||||
"notionalCap": "30000000",
|
"notionalCap": "5000000",
|
||||||
"notionalFloor": "1000000",
|
"notionalFloor": "1000000",
|
||||||
"maintMarginRatio": "0.5",
|
"maintMarginRatio": "0.5",
|
||||||
"cum": "386950.0"
|
"cum": "386950.0"
|
||||||
@ -14576,13 +15034,13 @@
|
|||||||
"tier": 6.0,
|
"tier": 6.0,
|
||||||
"currency": "USDT",
|
"currency": "USDT",
|
||||||
"minNotional": 1000000.0,
|
"minNotional": 1000000.0,
|
||||||
"maxNotional": 30000000.0,
|
"maxNotional": 5000000.0,
|
||||||
"maintenanceMarginRate": 0.5,
|
"maintenanceMarginRate": 0.5,
|
||||||
"maxLeverage": 1.0,
|
"maxLeverage": 1.0,
|
||||||
"info": {
|
"info": {
|
||||||
"bracket": "6",
|
"bracket": "6",
|
||||||
"initialLeverage": "1",
|
"initialLeverage": "1",
|
||||||
"notionalCap": "30000000",
|
"notionalCap": "5000000",
|
||||||
"notionalFloor": "1000000",
|
"notionalFloor": "1000000",
|
||||||
"maintMarginRatio": "0.5",
|
"maintMarginRatio": "0.5",
|
||||||
"cum": "386950.0"
|
"cum": "386950.0"
|
||||||
@ -15487,6 +15945,104 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"SPELL/USDT": [
|
||||||
|
{
|
||||||
|
"tier": 1.0,
|
||||||
|
"currency": "USDT",
|
||||||
|
"minNotional": 0.0,
|
||||||
|
"maxNotional": 5000.0,
|
||||||
|
"maintenanceMarginRate": 0.01,
|
||||||
|
"maxLeverage": 25.0,
|
||||||
|
"info": {
|
||||||
|
"bracket": "1",
|
||||||
|
"initialLeverage": "25",
|
||||||
|
"notionalCap": "5000",
|
||||||
|
"notionalFloor": "0",
|
||||||
|
"maintMarginRatio": "0.01",
|
||||||
|
"cum": "0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tier": 2.0,
|
||||||
|
"currency": "USDT",
|
||||||
|
"minNotional": 5000.0,
|
||||||
|
"maxNotional": 25000.0,
|
||||||
|
"maintenanceMarginRate": 0.025,
|
||||||
|
"maxLeverage": 20.0,
|
||||||
|
"info": {
|
||||||
|
"bracket": "2",
|
||||||
|
"initialLeverage": "20",
|
||||||
|
"notionalCap": "25000",
|
||||||
|
"notionalFloor": "5000",
|
||||||
|
"maintMarginRatio": "0.025",
|
||||||
|
"cum": "75.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tier": 3.0,
|
||||||
|
"currency": "USDT",
|
||||||
|
"minNotional": 25000.0,
|
||||||
|
"maxNotional": 100000.0,
|
||||||
|
"maintenanceMarginRate": 0.05,
|
||||||
|
"maxLeverage": 10.0,
|
||||||
|
"info": {
|
||||||
|
"bracket": "3",
|
||||||
|
"initialLeverage": "10",
|
||||||
|
"notionalCap": "100000",
|
||||||
|
"notionalFloor": "25000",
|
||||||
|
"maintMarginRatio": "0.05",
|
||||||
|
"cum": "700.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tier": 4.0,
|
||||||
|
"currency": "USDT",
|
||||||
|
"minNotional": 100000.0,
|
||||||
|
"maxNotional": 250000.0,
|
||||||
|
"maintenanceMarginRate": 0.1,
|
||||||
|
"maxLeverage": 5.0,
|
||||||
|
"info": {
|
||||||
|
"bracket": "4",
|
||||||
|
"initialLeverage": "5",
|
||||||
|
"notionalCap": "250000",
|
||||||
|
"notionalFloor": "100000",
|
||||||
|
"maintMarginRatio": "0.1",
|
||||||
|
"cum": "5700.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tier": 5.0,
|
||||||
|
"currency": "USDT",
|
||||||
|
"minNotional": 250000.0,
|
||||||
|
"maxNotional": 1000000.0,
|
||||||
|
"maintenanceMarginRate": 0.125,
|
||||||
|
"maxLeverage": 2.0,
|
||||||
|
"info": {
|
||||||
|
"bracket": "5",
|
||||||
|
"initialLeverage": "2",
|
||||||
|
"notionalCap": "1000000",
|
||||||
|
"notionalFloor": "250000",
|
||||||
|
"maintMarginRatio": "0.125",
|
||||||
|
"cum": "11950.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tier": 6.0,
|
||||||
|
"currency": "USDT",
|
||||||
|
"minNotional": 1000000.0,
|
||||||
|
"maxNotional": 5000000.0,
|
||||||
|
"maintenanceMarginRate": 0.5,
|
||||||
|
"maxLeverage": 1.0,
|
||||||
|
"info": {
|
||||||
|
"bracket": "6",
|
||||||
|
"initialLeverage": "1",
|
||||||
|
"notionalCap": "5000000",
|
||||||
|
"notionalFloor": "1000000",
|
||||||
|
"maintMarginRatio": "0.5",
|
||||||
|
"cum": "386950.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
"SRM/USDT": [
|
"SRM/USDT": [
|
||||||
{
|
{
|
||||||
"tier": 1.0,
|
"tier": 1.0,
|
||||||
@ -15585,6 +16141,104 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"STG/USDT": [
|
||||||
|
{
|
||||||
|
"tier": 1.0,
|
||||||
|
"currency": "USDT",
|
||||||
|
"minNotional": 0.0,
|
||||||
|
"maxNotional": 5000.0,
|
||||||
|
"maintenanceMarginRate": 0.01,
|
||||||
|
"maxLeverage": 25.0,
|
||||||
|
"info": {
|
||||||
|
"bracket": "1",
|
||||||
|
"initialLeverage": "25",
|
||||||
|
"notionalCap": "5000",
|
||||||
|
"notionalFloor": "0",
|
||||||
|
"maintMarginRatio": "0.01",
|
||||||
|
"cum": "0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tier": 2.0,
|
||||||
|
"currency": "USDT",
|
||||||
|
"minNotional": 5000.0,
|
||||||
|
"maxNotional": 25000.0,
|
||||||
|
"maintenanceMarginRate": 0.025,
|
||||||
|
"maxLeverage": 20.0,
|
||||||
|
"info": {
|
||||||
|
"bracket": "2",
|
||||||
|
"initialLeverage": "20",
|
||||||
|
"notionalCap": "25000",
|
||||||
|
"notionalFloor": "5000",
|
||||||
|
"maintMarginRatio": "0.025",
|
||||||
|
"cum": "75.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tier": 3.0,
|
||||||
|
"currency": "USDT",
|
||||||
|
"minNotional": 25000.0,
|
||||||
|
"maxNotional": 100000.0,
|
||||||
|
"maintenanceMarginRate": 0.05,
|
||||||
|
"maxLeverage": 10.0,
|
||||||
|
"info": {
|
||||||
|
"bracket": "3",
|
||||||
|
"initialLeverage": "10",
|
||||||
|
"notionalCap": "100000",
|
||||||
|
"notionalFloor": "25000",
|
||||||
|
"maintMarginRatio": "0.05",
|
||||||
|
"cum": "700.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tier": 4.0,
|
||||||
|
"currency": "USDT",
|
||||||
|
"minNotional": 100000.0,
|
||||||
|
"maxNotional": 250000.0,
|
||||||
|
"maintenanceMarginRate": 0.1,
|
||||||
|
"maxLeverage": 5.0,
|
||||||
|
"info": {
|
||||||
|
"bracket": "4",
|
||||||
|
"initialLeverage": "5",
|
||||||
|
"notionalCap": "250000",
|
||||||
|
"notionalFloor": "100000",
|
||||||
|
"maintMarginRatio": "0.1",
|
||||||
|
"cum": "5700.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tier": 5.0,
|
||||||
|
"currency": "USDT",
|
||||||
|
"minNotional": 250000.0,
|
||||||
|
"maxNotional": 1000000.0,
|
||||||
|
"maintenanceMarginRate": 0.125,
|
||||||
|
"maxLeverage": 2.0,
|
||||||
|
"info": {
|
||||||
|
"bracket": "5",
|
||||||
|
"initialLeverage": "2",
|
||||||
|
"notionalCap": "1000000",
|
||||||
|
"notionalFloor": "250000",
|
||||||
|
"maintMarginRatio": "0.125",
|
||||||
|
"cum": "11950.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tier": 6.0,
|
||||||
|
"currency": "USDT",
|
||||||
|
"minNotional": 1000000.0,
|
||||||
|
"maxNotional": 5000000.0,
|
||||||
|
"maintenanceMarginRate": 0.5,
|
||||||
|
"maxLeverage": 1.0,
|
||||||
|
"info": {
|
||||||
|
"bracket": "6",
|
||||||
|
"initialLeverage": "1",
|
||||||
|
"notionalCap": "5000000",
|
||||||
|
"notionalFloor": "1000000",
|
||||||
|
"maintMarginRatio": "0.5",
|
||||||
|
"cum": "386950.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
"STMX/USDT": [
|
"STMX/USDT": [
|
||||||
{
|
{
|
||||||
"tier": 1.0,
|
"tier": 1.0,
|
||||||
@ -16176,13 +16830,13 @@
|
|||||||
"tier": 5.0,
|
"tier": 5.0,
|
||||||
"currency": "BUSD",
|
"currency": "BUSD",
|
||||||
"minNotional": 1000000.0,
|
"minNotional": 1000000.0,
|
||||||
"maxNotional": 30000000.0,
|
"maxNotional": 5000000.0,
|
||||||
"maintenanceMarginRate": 0.5,
|
"maintenanceMarginRate": 0.5,
|
||||||
"maxLeverage": 1.0,
|
"maxLeverage": 1.0,
|
||||||
"info": {
|
"info": {
|
||||||
"bracket": "5",
|
"bracket": "5",
|
||||||
"initialLeverage": "1",
|
"initialLeverage": "1",
|
||||||
"notionalCap": "30000000",
|
"notionalCap": "5000000",
|
||||||
"notionalFloor": "1000000",
|
"notionalFloor": "1000000",
|
||||||
"maintMarginRatio": "0.5",
|
"maintMarginRatio": "0.5",
|
||||||
"cum": "386875.0"
|
"cum": "386875.0"
|
||||||
@ -16470,13 +17124,13 @@
|
|||||||
"tier": 6.0,
|
"tier": 6.0,
|
||||||
"currency": "USDT",
|
"currency": "USDT",
|
||||||
"minNotional": 1000000.0,
|
"minNotional": 1000000.0,
|
||||||
"maxNotional": 30000000.0,
|
"maxNotional": 5000000.0,
|
||||||
"maintenanceMarginRate": 0.5,
|
"maintenanceMarginRate": 0.5,
|
||||||
"maxLeverage": 1.0,
|
"maxLeverage": 1.0,
|
||||||
"info": {
|
"info": {
|
||||||
"bracket": "6",
|
"bracket": "6",
|
||||||
"initialLeverage": "1",
|
"initialLeverage": "1",
|
||||||
"notionalCap": "30000000",
|
"notionalCap": "5000000",
|
||||||
"notionalFloor": "1000000",
|
"notionalFloor": "1000000",
|
||||||
"maintMarginRatio": "0.5",
|
"maintMarginRatio": "0.5",
|
||||||
"cum": "386950.0"
|
"cum": "386950.0"
|
||||||
|
@ -2304,7 +2304,7 @@ class Exchange:
|
|||||||
updated = tiers.get('updated')
|
updated = tiers.get('updated')
|
||||||
if updated:
|
if updated:
|
||||||
updated_dt = parser.parse(updated)
|
updated_dt = parser.parse(updated)
|
||||||
if updated_dt < datetime.now(timezone.utc) - timedelta(days=1):
|
if updated_dt < datetime.now(timezone.utc) - timedelta(weeks=4):
|
||||||
logger.info("Cached leverage tiers are outdated. Will update.")
|
logger.info("Cached leverage tiers are outdated. Will update.")
|
||||||
return None
|
return None
|
||||||
return tiers['data']
|
return tiers['data']
|
||||||
|
@ -355,7 +355,7 @@ class FreqaiDataDrawer:
|
|||||||
for dir in model_folders:
|
for dir in model_folders:
|
||||||
result = pattern.match(str(dir.name))
|
result = pattern.match(str(dir.name))
|
||||||
if result is None:
|
if result is None:
|
||||||
break
|
continue
|
||||||
coin = result.group(1)
|
coin = result.group(1)
|
||||||
timestamp = result.group(2)
|
timestamp = result.group(2)
|
||||||
|
|
||||||
|
85
freqtrade/freqai/prediction_models/XGBoostClassifier.py
Normal file
85
freqtrade/freqai/prediction_models/XGBoostClassifier.py
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
import logging
|
||||||
|
from typing import Any, Dict, Tuple
|
||||||
|
|
||||||
|
import numpy as np
|
||||||
|
import numpy.typing as npt
|
||||||
|
import pandas as pd
|
||||||
|
from pandas import DataFrame
|
||||||
|
from pandas.api.types import is_integer_dtype
|
||||||
|
from sklearn.preprocessing import LabelEncoder
|
||||||
|
from xgboost import XGBClassifier
|
||||||
|
|
||||||
|
from freqtrade.freqai.base_models.BaseClassifierModel import BaseClassifierModel
|
||||||
|
from freqtrade.freqai.data_kitchen import FreqaiDataKitchen
|
||||||
|
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class XGBoostClassifier(BaseClassifierModel):
|
||||||
|
"""
|
||||||
|
User created prediction model. The class needs to override three necessary
|
||||||
|
functions, predict(), train(), fit(). The class inherits ModelHandler which
|
||||||
|
has its own DataHandler where data is held, saved, loaded, and managed.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def fit(self, data_dictionary: Dict, dk: FreqaiDataKitchen, **kwargs) -> Any:
|
||||||
|
"""
|
||||||
|
User sets up the training and test data to fit their desired model here
|
||||||
|
:params:
|
||||||
|
:data_dictionary: the dictionary constructed by DataHandler to hold
|
||||||
|
all the training and test data/labels.
|
||||||
|
"""
|
||||||
|
|
||||||
|
X = data_dictionary["train_features"].to_numpy()
|
||||||
|
y = data_dictionary["train_labels"].to_numpy()[:, 0]
|
||||||
|
|
||||||
|
le = LabelEncoder()
|
||||||
|
if not is_integer_dtype(y):
|
||||||
|
y = pd.Series(le.fit_transform(y), dtype="int64")
|
||||||
|
|
||||||
|
if self.freqai_info.get('data_split_parameters', {}).get('test_size', 0.1) == 0:
|
||||||
|
eval_set = None
|
||||||
|
else:
|
||||||
|
test_features = data_dictionary["test_features"].to_numpy()
|
||||||
|
test_labels = data_dictionary["test_labels"].to_numpy()[:, 0]
|
||||||
|
|
||||||
|
if not is_integer_dtype(test_labels):
|
||||||
|
test_labels = pd.Series(le.transform(test_labels), dtype="int64")
|
||||||
|
|
||||||
|
eval_set = [(test_features, test_labels)]
|
||||||
|
|
||||||
|
train_weights = data_dictionary["train_weights"]
|
||||||
|
|
||||||
|
init_model = self.get_init_model(dk.pair)
|
||||||
|
|
||||||
|
model = XGBClassifier(**self.model_training_parameters)
|
||||||
|
|
||||||
|
model.fit(X=X, y=y, eval_set=eval_set, sample_weight=train_weights,
|
||||||
|
xgb_model=init_model)
|
||||||
|
|
||||||
|
return model
|
||||||
|
|
||||||
|
def predict(
|
||||||
|
self, unfiltered_df: DataFrame, dk: FreqaiDataKitchen, **kwargs
|
||||||
|
) -> Tuple[DataFrame, npt.NDArray[np.int_]]:
|
||||||
|
"""
|
||||||
|
Filter the prediction features data and predict with it.
|
||||||
|
:param: unfiltered_df: Full dataframe for the current backtest period.
|
||||||
|
:return:
|
||||||
|
:pred_df: dataframe containing the predictions
|
||||||
|
:do_predict: np.array of 1s and 0s to indicate places where freqai needed to remove
|
||||||
|
data (NaNs) or felt uncertain about data (PCA and DI index)
|
||||||
|
"""
|
||||||
|
|
||||||
|
(pred_df, dk.do_predict) = super().predict(unfiltered_df, dk, **kwargs)
|
||||||
|
|
||||||
|
le = LabelEncoder()
|
||||||
|
label = dk.label_list[0]
|
||||||
|
labels_before = list(dk.data['labels_std'].keys())
|
||||||
|
labels_after = le.fit_transform(labels_before).tolist()
|
||||||
|
pred_df[label] = le.inverse_transform(pred_df[label])
|
||||||
|
pred_df = pred_df.rename(
|
||||||
|
columns={labels_after[i]: labels_before[i] for i in range(len(labels_before))})
|
||||||
|
|
||||||
|
return (pred_df, dk.do_predict)
|
@ -1072,6 +1072,7 @@ class FreqtradeBot(LoggingMixin):
|
|||||||
order_obj = Order.parse_from_ccxt_object(stoploss_order, trade.pair, 'stoploss')
|
order_obj = Order.parse_from_ccxt_object(stoploss_order, trade.pair, 'stoploss')
|
||||||
trade.orders.append(order_obj)
|
trade.orders.append(order_obj)
|
||||||
trade.stoploss_order_id = str(stoploss_order['id'])
|
trade.stoploss_order_id = str(stoploss_order['id'])
|
||||||
|
trade.stoploss_last_update = datetime.now(timezone.utc)
|
||||||
return True
|
return True
|
||||||
except InsufficientFundsError as e:
|
except InsufficientFundsError as e:
|
||||||
logger.warning(f"Unable to place stoploss order {e}.")
|
logger.warning(f"Unable to place stoploss order {e}.")
|
||||||
@ -1145,10 +1146,9 @@ class FreqtradeBot(LoggingMixin):
|
|||||||
if self.create_stoploss_order(trade=trade, stop_price=stop_price):
|
if self.create_stoploss_order(trade=trade, stop_price=stop_price):
|
||||||
# The above will return False if the placement failed and the trade was force-sold.
|
# The above will return False if the placement failed and the trade was force-sold.
|
||||||
# in which case the trade will be closed - which we must check below.
|
# in which case the trade will be closed - which we must check below.
|
||||||
trade.stoploss_last_update = datetime.utcnow()
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# If stoploss order is canceled for some reason we add it
|
# If stoploss order is canceled for some reason we add it again
|
||||||
if (trade.is_open
|
if (trade.is_open
|
||||||
and stoploss_order
|
and stoploss_order
|
||||||
and stoploss_order['status'] in ('canceled', 'cancelled')):
|
and stoploss_order['status'] in ('canceled', 'cancelled')):
|
||||||
@ -1186,7 +1186,8 @@ class FreqtradeBot(LoggingMixin):
|
|||||||
if self.exchange.stoploss_adjust(stoploss_norm, order, side=trade.exit_side):
|
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:
|
upd_req = datetime.now(timezone.utc) - timedelta(seconds=update_beat)
|
||||||
|
if trade.stoploss_last_update_utc and upd_req >= trade.stoploss_last_update_utc:
|
||||||
# cancelling the current stoploss on exchange first
|
# cancelling the current stoploss on exchange first
|
||||||
logger.info(f"Cancelling current stoploss on exchange for pair {trade.pair} "
|
logger.info(f"Cancelling current stoploss on exchange for pair {trade.pair} "
|
||||||
f"(orderid:{order['id']}) in order to add another one ...")
|
f"(orderid:{order['id']}) in order to add another one ...")
|
||||||
|
@ -812,14 +812,6 @@ class Backtesting:
|
|||||||
return trade
|
return trade
|
||||||
time_in_force = self.strategy.order_time_in_force['entry']
|
time_in_force = self.strategy.order_time_in_force['entry']
|
||||||
|
|
||||||
if not pos_adjust:
|
|
||||||
# Confirm trade entry:
|
|
||||||
if not strategy_safe_wrapper(self.strategy.confirm_trade_entry, default_retval=True)(
|
|
||||||
pair=pair, order_type=order_type, amount=stake_amount, rate=propose_rate,
|
|
||||||
time_in_force=time_in_force, current_time=current_time,
|
|
||||||
entry_tag=entry_tag, side=direction):
|
|
||||||
return trade
|
|
||||||
|
|
||||||
if stake_amount and (not min_stake_amount or stake_amount > min_stake_amount):
|
if stake_amount and (not min_stake_amount or stake_amount > min_stake_amount):
|
||||||
self.order_id_counter += 1
|
self.order_id_counter += 1
|
||||||
base_currency = self.exchange.get_pair_base_currency(pair)
|
base_currency = self.exchange.get_pair_base_currency(pair)
|
||||||
@ -834,6 +826,15 @@ class Backtesting:
|
|||||||
# Backcalculate actual stake amount.
|
# Backcalculate actual stake amount.
|
||||||
stake_amount = amount * propose_rate / leverage
|
stake_amount = amount * propose_rate / leverage
|
||||||
|
|
||||||
|
if not pos_adjust:
|
||||||
|
# Confirm trade entry:
|
||||||
|
if not strategy_safe_wrapper(
|
||||||
|
self.strategy.confirm_trade_entry, default_retval=True)(
|
||||||
|
pair=pair, order_type=order_type, amount=amount, rate=propose_rate,
|
||||||
|
time_in_force=time_in_force, current_time=current_time,
|
||||||
|
entry_tag=entry_tag, side=direction):
|
||||||
|
return trade
|
||||||
|
|
||||||
is_short = (direction == 'short')
|
is_short = (direction == 'short')
|
||||||
# Necessary for Margin trading. Disabled until support is enabled.
|
# Necessary for Margin trading. Disabled until support is enabled.
|
||||||
# interest_rate = self.exchange.get_interest_rate()
|
# interest_rate = self.exchange.get_interest_rate()
|
||||||
|
@ -290,7 +290,7 @@ class Hyperopt:
|
|||||||
# noinspection PyProtectedMember
|
# noinspection PyProtectedMember
|
||||||
attr.value = params_dict[attr_name]
|
attr.value = params_dict[attr_name]
|
||||||
|
|
||||||
def generate_optimizer(self, raw_params: List[Any], iteration=None) -> Dict:
|
def generate_optimizer(self, raw_params: List[Any]) -> Dict[str, Any]:
|
||||||
"""
|
"""
|
||||||
Used Optimize function.
|
Used Optimize function.
|
||||||
Called once per epoch to optimize whatever is configured.
|
Called once per epoch to optimize whatever is configured.
|
||||||
@ -410,9 +410,11 @@ class Hyperopt:
|
|||||||
model_queue_size=SKOPT_MODEL_QUEUE_SIZE,
|
model_queue_size=SKOPT_MODEL_QUEUE_SIZE,
|
||||||
)
|
)
|
||||||
|
|
||||||
def run_optimizer_parallel(self, parallel, asked, i) -> List:
|
def run_optimizer_parallel(
|
||||||
|
self, parallel: Parallel, asked: List[List]) -> List[Dict[str, Any]]:
|
||||||
|
""" Start optimizer in a parallel way """
|
||||||
return parallel(delayed(
|
return parallel(delayed(
|
||||||
wrap_non_picklable_objects(self.generate_optimizer))(v, i) for v in asked)
|
wrap_non_picklable_objects(self.generate_optimizer))(v) for v in asked)
|
||||||
|
|
||||||
def _set_random_state(self, random_state: Optional[int]) -> int:
|
def _set_random_state(self, random_state: Optional[int]) -> int:
|
||||||
return random_state or random.randint(1, 2**16 - 1)
|
return random_state or random.randint(1, 2**16 - 1)
|
||||||
@ -491,6 +493,53 @@ class Hyperopt:
|
|||||||
else:
|
else:
|
||||||
return self.opt.ask(n_points=n_points), [False for _ in range(n_points)]
|
return self.opt.ask(n_points=n_points), [False for _ in range(n_points)]
|
||||||
|
|
||||||
|
def get_progressbar_widgets(self):
|
||||||
|
if self.print_colorized:
|
||||||
|
widgets = [
|
||||||
|
' [Epoch ', progressbar.Counter(), ' of ', str(self.total_epochs),
|
||||||
|
' (', progressbar.Percentage(), ')] ',
|
||||||
|
progressbar.Bar(marker=progressbar.AnimatedMarker(
|
||||||
|
fill='\N{FULL BLOCK}',
|
||||||
|
fill_wrap=Fore.GREEN + '{}' + Fore.RESET,
|
||||||
|
marker_wrap=Style.BRIGHT + '{}' + Style.RESET_ALL,
|
||||||
|
)),
|
||||||
|
' [', progressbar.ETA(), ', ', progressbar.Timer(), ']',
|
||||||
|
]
|
||||||
|
else:
|
||||||
|
widgets = [
|
||||||
|
' [Epoch ', progressbar.Counter(), ' of ', str(self.total_epochs),
|
||||||
|
' (', progressbar.Percentage(), ')] ',
|
||||||
|
progressbar.Bar(marker=progressbar.AnimatedMarker(
|
||||||
|
fill='\N{FULL BLOCK}',
|
||||||
|
)),
|
||||||
|
' [', progressbar.ETA(), ', ', progressbar.Timer(), ']',
|
||||||
|
]
|
||||||
|
return widgets
|
||||||
|
|
||||||
|
def evaluate_result(self, val: Dict[str, Any], current: int, is_random: bool):
|
||||||
|
"""
|
||||||
|
Evaluate results returned from generate_optimizer
|
||||||
|
"""
|
||||||
|
val['current_epoch'] = current
|
||||||
|
val['is_initial_point'] = current <= INITIAL_POINTS
|
||||||
|
|
||||||
|
logger.debug("Optimizer epoch evaluated: %s", val)
|
||||||
|
|
||||||
|
is_best = HyperoptTools.is_best_loss(val, self.current_best_loss)
|
||||||
|
# This value is assigned here and not in the optimization method
|
||||||
|
# to keep proper order in the list of results. That's because
|
||||||
|
# evaluations can take different time. Here they are aligned in the
|
||||||
|
# order they will be shown to the user.
|
||||||
|
val['is_best'] = is_best
|
||||||
|
val['is_random'] = is_random
|
||||||
|
self.print_results(val)
|
||||||
|
|
||||||
|
if is_best:
|
||||||
|
self.current_best_loss = val['loss']
|
||||||
|
self.current_best_epoch = val
|
||||||
|
|
||||||
|
self._save_result(val)
|
||||||
|
|
||||||
def start(self) -> None:
|
def start(self) -> None:
|
||||||
self.random_state = self._set_random_state(self.config.get('hyperopt_random_state'))
|
self.random_state = self._set_random_state(self.config.get('hyperopt_random_state'))
|
||||||
logger.info(f"Using optimizer random state: {self.random_state}")
|
logger.info(f"Using optimizer random state: {self.random_state}")
|
||||||
@ -526,64 +575,40 @@ class Hyperopt:
|
|||||||
logger.info(f'Effective number of parallel workers used: {jobs}')
|
logger.info(f'Effective number of parallel workers used: {jobs}')
|
||||||
|
|
||||||
# Define progressbar
|
# Define progressbar
|
||||||
if self.print_colorized:
|
widgets = self.get_progressbar_widgets()
|
||||||
widgets = [
|
|
||||||
' [Epoch ', progressbar.Counter(), ' of ', str(self.total_epochs),
|
|
||||||
' (', progressbar.Percentage(), ')] ',
|
|
||||||
progressbar.Bar(marker=progressbar.AnimatedMarker(
|
|
||||||
fill='\N{FULL BLOCK}',
|
|
||||||
fill_wrap=Fore.GREEN + '{}' + Fore.RESET,
|
|
||||||
marker_wrap=Style.BRIGHT + '{}' + Style.RESET_ALL,
|
|
||||||
)),
|
|
||||||
' [', progressbar.ETA(), ', ', progressbar.Timer(), ']',
|
|
||||||
]
|
|
||||||
else:
|
|
||||||
widgets = [
|
|
||||||
' [Epoch ', progressbar.Counter(), ' of ', str(self.total_epochs),
|
|
||||||
' (', progressbar.Percentage(), ')] ',
|
|
||||||
progressbar.Bar(marker=progressbar.AnimatedMarker(
|
|
||||||
fill='\N{FULL BLOCK}',
|
|
||||||
)),
|
|
||||||
' [', progressbar.ETA(), ', ', progressbar.Timer(), ']',
|
|
||||||
]
|
|
||||||
with progressbar.ProgressBar(
|
with progressbar.ProgressBar(
|
||||||
max_value=self.total_epochs, redirect_stdout=False, redirect_stderr=False,
|
max_value=self.total_epochs, redirect_stdout=False, redirect_stderr=False,
|
||||||
widgets=widgets
|
widgets=widgets
|
||||||
) as pbar:
|
) as pbar:
|
||||||
EVALS = ceil(self.total_epochs / jobs)
|
start = 0
|
||||||
for i in range(EVALS):
|
|
||||||
|
if self.analyze_per_epoch:
|
||||||
|
# First analysis not in parallel mode when using --analyze-per-epoch.
|
||||||
|
# This allows dataprovider to load it's informative cache.
|
||||||
|
asked, is_random = self.get_asked_points(n_points=1)
|
||||||
|
f_val0 = self.generate_optimizer(asked[0])
|
||||||
|
self.opt.tell(asked, [f_val0['loss']])
|
||||||
|
self.evaluate_result(f_val0, 1, is_random[0])
|
||||||
|
pbar.update(1)
|
||||||
|
start += 1
|
||||||
|
|
||||||
|
evals = ceil((self.total_epochs - start) / jobs)
|
||||||
|
for i in range(evals):
|
||||||
# Correct the number of epochs to be processed for the last
|
# Correct the number of epochs to be processed for the last
|
||||||
# iteration (should not exceed self.total_epochs in total)
|
# iteration (should not exceed self.total_epochs in total)
|
||||||
n_rest = (i + 1) * jobs - self.total_epochs
|
n_rest = (i + 1) * jobs - (self.total_epochs - start)
|
||||||
current_jobs = jobs - n_rest if n_rest > 0 else jobs
|
current_jobs = jobs - n_rest if n_rest > 0 else jobs
|
||||||
|
|
||||||
asked, is_random = self.get_asked_points(n_points=current_jobs)
|
asked, is_random = self.get_asked_points(n_points=current_jobs)
|
||||||
f_val = self.run_optimizer_parallel(parallel, asked, i)
|
f_val = self.run_optimizer_parallel(parallel, asked)
|
||||||
self.opt.tell(asked, [v['loss'] for v in f_val])
|
self.opt.tell(asked, [v['loss'] for v in f_val])
|
||||||
|
|
||||||
# Calculate progressbar outputs
|
# Calculate progressbar outputs
|
||||||
for j, val in enumerate(f_val):
|
for j, val in enumerate(f_val):
|
||||||
# Use human-friendly indexes here (starting from 1)
|
# Use human-friendly indexes here (starting from 1)
|
||||||
current = i * jobs + j + 1
|
current = i * jobs + j + 1 + start
|
||||||
val['current_epoch'] = current
|
|
||||||
val['is_initial_point'] = current <= INITIAL_POINTS
|
|
||||||
|
|
||||||
logger.debug(f"Optimizer epoch evaluated: {val}")
|
self.evaluate_result(val, current, is_random[j])
|
||||||
|
|
||||||
is_best = HyperoptTools.is_best_loss(val, self.current_best_loss)
|
|
||||||
# This value is assigned here and not in the optimization method
|
|
||||||
# to keep proper order in the list of results. That's because
|
|
||||||
# evaluations can take different time. Here they are aligned in the
|
|
||||||
# order they will be shown to the user.
|
|
||||||
val['is_best'] = is_best
|
|
||||||
val['is_random'] = is_random[j]
|
|
||||||
self.print_results(val)
|
|
||||||
|
|
||||||
if is_best:
|
|
||||||
self.current_best_loss = val['loss']
|
|
||||||
self.current_best_epoch = val
|
|
||||||
|
|
||||||
self._save_result(val)
|
|
||||||
|
|
||||||
pbar.update(current)
|
pbar.update(current)
|
||||||
|
|
||||||
|
@ -83,7 +83,7 @@ class Order(_DECL_BASE):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def safe_price(self) -> float:
|
def safe_price(self) -> float:
|
||||||
return self.average or self.price
|
return self.average or self.price or self.stop_price
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def safe_filled(self) -> float:
|
def safe_filled(self) -> float:
|
||||||
@ -376,6 +376,12 @@ class LocalTrade():
|
|||||||
def open_date_utc(self):
|
def open_date_utc(self):
|
||||||
return self.open_date.replace(tzinfo=timezone.utc)
|
return self.open_date.replace(tzinfo=timezone.utc)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def stoploss_last_update_utc(self):
|
||||||
|
if self.stoploss_last_update:
|
||||||
|
return self.stoploss_last_update.replace(tzinfo=timezone.utc)
|
||||||
|
return None
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def close_date_utc(self):
|
def close_date_utc(self):
|
||||||
return self.close_date.replace(tzinfo=timezone.utc)
|
return self.close_date.replace(tzinfo=timezone.utc)
|
||||||
@ -560,7 +566,6 @@ class LocalTrade():
|
|||||||
self.stop_loss = stop_loss_norm
|
self.stop_loss = stop_loss_norm
|
||||||
|
|
||||||
self.stop_loss_pct = -1 * abs(percent)
|
self.stop_loss_pct = -1 * abs(percent)
|
||||||
self.stoploss_last_update = datetime.utcnow()
|
|
||||||
|
|
||||||
def adjust_stop_loss(self, current_price: float, stoploss: float,
|
def adjust_stop_loss(self, current_price: float, stoploss: float,
|
||||||
initial: bool = False, refresh: bool = False) -> None:
|
initial: bool = False, refresh: bool = False) -> None:
|
||||||
|
@ -684,6 +684,22 @@ class IStrategy(ABC, HyperStrategyMixin):
|
|||||||
# END - Intended to be overridden by strategy
|
# END - Intended to be overridden by strategy
|
||||||
###
|
###
|
||||||
|
|
||||||
|
def __informative_pairs_freqai(self) -> ListPairsWithTimeframes:
|
||||||
|
"""
|
||||||
|
Create informative-pairs needed for FreqAI
|
||||||
|
"""
|
||||||
|
if self.config.get('freqai', {}).get('enabled', False):
|
||||||
|
whitelist_pairs = self.dp.current_whitelist()
|
||||||
|
candle_type = self.config.get('candle_type_def', CandleType.SPOT)
|
||||||
|
corr_pairs = self.config["freqai"]["feature_parameters"]["include_corr_pairlist"]
|
||||||
|
informative_pairs = []
|
||||||
|
for tf in self.config["freqai"]["feature_parameters"]["include_timeframes"]:
|
||||||
|
for pair in set(whitelist_pairs + corr_pairs):
|
||||||
|
informative_pairs.append((pair, tf, candle_type))
|
||||||
|
return informative_pairs
|
||||||
|
|
||||||
|
return []
|
||||||
|
|
||||||
def gather_informative_pairs(self) -> ListPairsWithTimeframes:
|
def gather_informative_pairs(self) -> ListPairsWithTimeframes:
|
||||||
"""
|
"""
|
||||||
Internal method which gathers all informative pairs (user or automatically defined).
|
Internal method which gathers all informative pairs (user or automatically defined).
|
||||||
@ -708,6 +724,7 @@ class IStrategy(ABC, HyperStrategyMixin):
|
|||||||
else:
|
else:
|
||||||
for pair in self.dp.current_whitelist():
|
for pair in self.dp.current_whitelist():
|
||||||
informative_pairs.append((pair, inf_data.timeframe, candle_type))
|
informative_pairs.append((pair, inf_data.timeframe, candle_type))
|
||||||
|
informative_pairs.extend(self.__informative_pairs_freqai())
|
||||||
return list(set(informative_pairs))
|
return list(set(informative_pairs))
|
||||||
|
|
||||||
def get_strategy_name(self) -> str:
|
def get_strategy_name(self) -> str:
|
||||||
|
@ -47,19 +47,6 @@ class FreqaiExampleStrategy(IStrategy):
|
|||||||
std_dev_multiplier_sell = CategoricalParameter(
|
std_dev_multiplier_sell = CategoricalParameter(
|
||||||
[0.1, 0.25, 0.4], space="sell", default=0.2, optimize=True)
|
[0.1, 0.25, 0.4], space="sell", default=0.2, optimize=True)
|
||||||
|
|
||||||
def informative_pairs(self):
|
|
||||||
whitelist_pairs = self.dp.current_whitelist()
|
|
||||||
corr_pairs = self.config["freqai"]["feature_parameters"]["include_corr_pairlist"]
|
|
||||||
informative_pairs = []
|
|
||||||
for tf in self.config["freqai"]["feature_parameters"]["include_timeframes"]:
|
|
||||||
for pair in whitelist_pairs:
|
|
||||||
informative_pairs.append((pair, tf))
|
|
||||||
for pair in corr_pairs:
|
|
||||||
if pair in whitelist_pairs:
|
|
||||||
continue # avoid duplication
|
|
||||||
informative_pairs.append((pair, tf))
|
|
||||||
return informative_pairs
|
|
||||||
|
|
||||||
def populate_any_indicators(
|
def populate_any_indicators(
|
||||||
self, pair, df, tf, informative=None, set_generalized_indicators=False
|
self, pair, df, tf, informative=None, set_generalized_indicators=False
|
||||||
):
|
):
|
||||||
|
@ -95,20 +95,6 @@ class FreqaiExampleHybridStrategy(IStrategy):
|
|||||||
short_rsi = IntParameter(low=51, high=100, default=70, space='sell', optimize=True, load=True)
|
short_rsi = IntParameter(low=51, high=100, default=70, space='sell', optimize=True, load=True)
|
||||||
exit_short_rsi = IntParameter(low=1, high=50, default=30, space='buy', optimize=True, load=True)
|
exit_short_rsi = IntParameter(low=1, high=50, default=30, space='buy', optimize=True, load=True)
|
||||||
|
|
||||||
# FreqAI required function, leave as is or add additional informatives to existing structure.
|
|
||||||
def informative_pairs(self):
|
|
||||||
whitelist_pairs = self.dp.current_whitelist()
|
|
||||||
corr_pairs = self.config["freqai"]["feature_parameters"]["include_corr_pairlist"]
|
|
||||||
informative_pairs = []
|
|
||||||
for tf in self.config["freqai"]["feature_parameters"]["include_timeframes"]:
|
|
||||||
for pair in whitelist_pairs:
|
|
||||||
informative_pairs.append((pair, tf))
|
|
||||||
for pair in corr_pairs:
|
|
||||||
if pair in whitelist_pairs:
|
|
||||||
continue # avoid duplication
|
|
||||||
informative_pairs.append((pair, tf))
|
|
||||||
return informative_pairs
|
|
||||||
|
|
||||||
# FreqAI required function, user can add or remove indicators, but general structure
|
# FreqAI required function, user can add or remove indicators, but general structure
|
||||||
# must stay the same.
|
# must stay the same.
|
||||||
def populate_any_indicators(
|
def populate_any_indicators(
|
||||||
|
@ -49,6 +49,8 @@ theme:
|
|||||||
logo: "images/logo.png"
|
logo: "images/logo.png"
|
||||||
favicon: "images/logo.png"
|
favicon: "images/logo.png"
|
||||||
custom_dir: "docs/overrides"
|
custom_dir: "docs/overrides"
|
||||||
|
features:
|
||||||
|
- search.share
|
||||||
palette:
|
palette:
|
||||||
- scheme: default
|
- scheme: default
|
||||||
primary: "blue grey"
|
primary: "blue grey"
|
||||||
|
@ -25,6 +25,6 @@ nbconvert==7.0.0
|
|||||||
# mypy types
|
# mypy types
|
||||||
types-cachetools==5.2.1
|
types-cachetools==5.2.1
|
||||||
types-filelock==3.2.7
|
types-filelock==3.2.7
|
||||||
types-requests==2.28.9
|
types-requests==2.28.10
|
||||||
types-tabulate==0.8.11
|
types-tabulate==0.8.11
|
||||||
types-python-dateutil==2.8.19
|
types-python-dateutil==2.8.19
|
||||||
|
@ -1,18 +1,18 @@
|
|||||||
numpy==1.23.2
|
numpy==1.23.3
|
||||||
pandas==1.4.4
|
pandas==1.4.4
|
||||||
pandas-ta==0.3.14b
|
pandas-ta==0.3.14b
|
||||||
|
|
||||||
ccxt==1.93.3
|
ccxt==1.93.35
|
||||||
# Pin cryptography for now due to rust build errors with piwheels
|
# Pin cryptography for now due to rust build errors with piwheels
|
||||||
cryptography==37.0.4
|
cryptography==38.0.1
|
||||||
aiohttp==3.8.1
|
aiohttp==3.8.1
|
||||||
SQLAlchemy==1.4.40
|
SQLAlchemy==1.4.41
|
||||||
python-telegram-bot==13.14
|
python-telegram-bot==13.14
|
||||||
arrow==1.2.3
|
arrow==1.2.3
|
||||||
cachetools==4.2.2
|
cachetools==4.2.2
|
||||||
requests==2.28.1
|
requests==2.28.1
|
||||||
urllib3==1.26.12
|
urllib3==1.26.12
|
||||||
jsonschema==4.15.0
|
jsonschema==4.16.0
|
||||||
TA-Lib==0.4.24
|
TA-Lib==0.4.24
|
||||||
technical==1.3.0
|
technical==1.3.0
|
||||||
tabulate==0.8.10
|
tabulate==0.8.10
|
||||||
@ -34,10 +34,10 @@ orjson==3.8.0
|
|||||||
sdnotify==0.3.2
|
sdnotify==0.3.2
|
||||||
|
|
||||||
# API Server
|
# API Server
|
||||||
fastapi==0.82.0
|
fastapi==0.83.0
|
||||||
uvicorn==0.18.3
|
uvicorn==0.18.3
|
||||||
pyjwt==2.4.0
|
pyjwt==2.4.0
|
||||||
aiofiles==0.8.0
|
aiofiles==22.1.0
|
||||||
psutil==5.9.2
|
psutil==5.9.2
|
||||||
|
|
||||||
# Support for colorized terminal output
|
# Support for colorized terminal output
|
||||||
|
@ -23,7 +23,7 @@ from tests.exchange.test_exchange import ccxt_exceptionhandlers
|
|||||||
def test_stoploss_order_binance(default_conf, mocker, limitratio, expected, side, trademode):
|
def test_stoploss_order_binance(default_conf, mocker, limitratio, expected, side, trademode):
|
||||||
api_mock = MagicMock()
|
api_mock = MagicMock()
|
||||||
order_id = 'test_prod_buy_{}'.format(randint(0, 10 ** 6))
|
order_id = 'test_prod_buy_{}'.format(randint(0, 10 ** 6))
|
||||||
order_type = 'stop_loss_limit' if trademode == TradingMode.SPOT else 'stop'
|
order_type = 'stop_loss_limit' if trademode == TradingMode.SPOT else 'limit'
|
||||||
|
|
||||||
api_mock.create_order = MagicMock(return_value={
|
api_mock.create_order = MagicMock(return_value={
|
||||||
'id': order_id,
|
'id': order_id,
|
||||||
@ -45,12 +45,15 @@ def test_stoploss_order_binance(default_conf, mocker, limitratio, expected, side
|
|||||||
amount=1,
|
amount=1,
|
||||||
stop_price=190,
|
stop_price=190,
|
||||||
side=side,
|
side=side,
|
||||||
order_types={'stoploss_on_exchange_limit_ratio': 1.05},
|
order_types={'stoploss': 'limit', 'stoploss_on_exchange_limit_ratio': 1.05},
|
||||||
leverage=1.0
|
leverage=1.0
|
||||||
)
|
)
|
||||||
|
|
||||||
api_mock.create_order.reset_mock()
|
api_mock.create_order.reset_mock()
|
||||||
order_types = {} if limitratio is None else {'stoploss_on_exchange_limit_ratio': limitratio}
|
order_types = {'stoploss': 'limit'}
|
||||||
|
if limitratio is not None:
|
||||||
|
order_types.update({'stoploss_on_exchange_limit_ratio': limitratio})
|
||||||
|
|
||||||
order = exchange.stoploss(
|
order = exchange.stoploss(
|
||||||
pair='ETH/BTC',
|
pair='ETH/BTC',
|
||||||
amount=1,
|
amount=1,
|
||||||
|
@ -297,7 +297,7 @@ class TestCCXTExchange():
|
|||||||
def test_ccxt__async_get_candle_history(self, exchange):
|
def test_ccxt__async_get_candle_history(self, exchange):
|
||||||
exchange, exchangename = exchange
|
exchange, exchangename = exchange
|
||||||
# For some weired reason, this test returns random lengths for bittrex.
|
# For some weired reason, this test returns random lengths for bittrex.
|
||||||
if not exchange._ft_has['ohlcv_has_history'] or exchangename in ('bittrex', 'gateio'):
|
if not exchange._ft_has['ohlcv_has_history'] or exchangename in ('bittrex'):
|
||||||
return
|
return
|
||||||
pair = EXCHANGES[exchangename]['pair']
|
pair = EXCHANGES[exchangename]['pair']
|
||||||
timeframe = EXCHANGES[exchangename]['timeframe']
|
timeframe = EXCHANGES[exchangename]['timeframe']
|
||||||
|
@ -472,7 +472,7 @@ def test_load_leverage_tiers_okx(default_conf, mocker, markets, tmpdir, caplog,
|
|||||||
|
|
||||||
api_mock.fetch_market_leverage_tiers.call_count == 0
|
api_mock.fetch_market_leverage_tiers.call_count == 0
|
||||||
# 2 day passes ...
|
# 2 day passes ...
|
||||||
time_machine.move_to(datetime.now() + timedelta(days=2))
|
time_machine.move_to(datetime.now() + timedelta(weeks=5))
|
||||||
exchange.load_leverage_tiers()
|
exchange.load_leverage_tiers()
|
||||||
|
|
||||||
assert log_has(logmsg, caplog)
|
assert log_has(logmsg, caplog)
|
||||||
|
@ -9,6 +9,7 @@ import pytest
|
|||||||
from freqtrade.configuration import TimeRange
|
from freqtrade.configuration import TimeRange
|
||||||
from freqtrade.data.dataprovider import DataProvider
|
from freqtrade.data.dataprovider import DataProvider
|
||||||
from freqtrade.freqai.data_kitchen import FreqaiDataKitchen
|
from freqtrade.freqai.data_kitchen import FreqaiDataKitchen
|
||||||
|
from freqtrade.plugins.pairlistmanager import PairListManager
|
||||||
from tests.conftest import get_patched_exchange, log_has_re
|
from tests.conftest import get_patched_exchange, log_has_re
|
||||||
from tests.freqai.conftest import get_patched_freqai_strategy
|
from tests.freqai.conftest import get_patched_freqai_strategy
|
||||||
|
|
||||||
@ -100,6 +101,7 @@ def test_extract_data_and_train_model_MultiTargets(mocker, freqai_conf, model):
|
|||||||
@pytest.mark.parametrize('model', [
|
@pytest.mark.parametrize('model', [
|
||||||
'LightGBMClassifier',
|
'LightGBMClassifier',
|
||||||
'CatboostClassifier',
|
'CatboostClassifier',
|
||||||
|
'XGBoostClassifier',
|
||||||
])
|
])
|
||||||
def test_extract_data_and_train_model_Classifiers(mocker, freqai_conf, model):
|
def test_extract_data_and_train_model_Classifiers(mocker, freqai_conf, model):
|
||||||
if is_arm() and model == 'CatboostClassifier':
|
if is_arm() and model == 'CatboostClassifier':
|
||||||
@ -340,3 +342,27 @@ def test_spice_rack(mocker, default_conf, tmpdir):
|
|||||||
|
|
||||||
assert 'freqai' in freqai_conf
|
assert 'freqai' in freqai_conf
|
||||||
assert strategy.freqai
|
assert strategy.freqai
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('timeframes,corr_pairs', [
|
||||||
|
(['5m'], ['ADA/BTC', 'DASH/BTC']),
|
||||||
|
(['5m'], ['ADA/BTC', 'DASH/BTC', 'ETH/USDT']),
|
||||||
|
(['5m', '15m'], ['ADA/BTC', 'DASH/BTC', 'ETH/USDT']),
|
||||||
|
])
|
||||||
|
def test_freqai_informative_pairs(mocker, freqai_conf, timeframes, corr_pairs):
|
||||||
|
freqai_conf['freqai']['feature_parameters'].update({
|
||||||
|
'include_timeframes': timeframes,
|
||||||
|
'include_corr_pairlist': corr_pairs,
|
||||||
|
|
||||||
|
})
|
||||||
|
strategy = get_patched_freqai_strategy(mocker, freqai_conf)
|
||||||
|
exchange = get_patched_exchange(mocker, freqai_conf)
|
||||||
|
pairlists = PairListManager(exchange, freqai_conf)
|
||||||
|
strategy.dp = DataProvider(freqai_conf, exchange, pairlists)
|
||||||
|
pairlist = strategy.dp.current_whitelist()
|
||||||
|
|
||||||
|
pairs_a = strategy.informative_pairs()
|
||||||
|
assert len(pairs_a) == 0
|
||||||
|
pairs_b = strategy.gather_informative_pairs()
|
||||||
|
# we expect unique pairs * timeframes
|
||||||
|
assert len(pairs_b) == len(set(pairlist + corr_pairs)) * len(timeframes)
|
||||||
|
@ -922,6 +922,45 @@ def test_in_strategy_auto_hyperopt_with_parallel(mocker, hyperopt_conf, tmpdir,
|
|||||||
hyperopt.start()
|
hyperopt.start()
|
||||||
|
|
||||||
|
|
||||||
|
def test_in_strategy_auto_hyperopt_per_epoch(mocker, hyperopt_conf, tmpdir, fee) -> None:
|
||||||
|
patch_exchange(mocker)
|
||||||
|
mocker.patch('freqtrade.exchange.Exchange.get_fee', fee)
|
||||||
|
(Path(tmpdir) / 'hyperopt_results').mkdir(parents=True)
|
||||||
|
|
||||||
|
hyperopt_conf.update({
|
||||||
|
'strategy': 'HyperoptableStrategy',
|
||||||
|
'user_data_dir': Path(tmpdir),
|
||||||
|
'hyperopt_random_state': 42,
|
||||||
|
'spaces': ['all'],
|
||||||
|
'epochs': 3,
|
||||||
|
'analyze_per_epoch': True,
|
||||||
|
})
|
||||||
|
go = mocker.patch('freqtrade.optimize.hyperopt.Hyperopt.generate_optimizer',
|
||||||
|
return_value={
|
||||||
|
'loss': 0.05,
|
||||||
|
'results_explanation': 'foo result', 'params': {},
|
||||||
|
'results_metrics': generate_result_metrics(),
|
||||||
|
})
|
||||||
|
hyperopt = Hyperopt(hyperopt_conf)
|
||||||
|
hyperopt.backtesting.exchange.get_max_leverage = MagicMock(return_value=1.0)
|
||||||
|
assert isinstance(hyperopt.custom_hyperopt, HyperOptAuto)
|
||||||
|
assert isinstance(hyperopt.backtesting.strategy.buy_rsi, IntParameter)
|
||||||
|
assert hyperopt.backtesting.strategy.bot_loop_started is True
|
||||||
|
|
||||||
|
assert hyperopt.backtesting.strategy.buy_rsi.in_space is True
|
||||||
|
assert hyperopt.backtesting.strategy.buy_rsi.value == 35
|
||||||
|
assert hyperopt.backtesting.strategy.sell_rsi.value == 74
|
||||||
|
assert hyperopt.backtesting.strategy.protection_cooldown_lookback.value == 30
|
||||||
|
buy_rsi_range = hyperopt.backtesting.strategy.buy_rsi.range
|
||||||
|
assert isinstance(buy_rsi_range, range)
|
||||||
|
# Range from 0 - 50 (inclusive)
|
||||||
|
assert len(list(buy_rsi_range)) == 51
|
||||||
|
|
||||||
|
hyperopt.start()
|
||||||
|
# backtesting should be called 3 times (once per epoch)
|
||||||
|
assert go.call_count == 3
|
||||||
|
|
||||||
|
|
||||||
def test_SKDecimal():
|
def test_SKDecimal():
|
||||||
space = SKDecimal(1, 2, decimals=2)
|
space = SKDecimal(1, 2, decimals=2)
|
||||||
assert 1.5 in space
|
assert 1.5 in space
|
||||||
|
@ -43,19 +43,6 @@ class freqai_test_multimodel_strat(IStrategy):
|
|||||||
)
|
)
|
||||||
max_roi_time_long = IntParameter(0, 800, default=400, space="sell", optimize=False, load=True)
|
max_roi_time_long = IntParameter(0, 800, default=400, space="sell", optimize=False, load=True)
|
||||||
|
|
||||||
def informative_pairs(self):
|
|
||||||
whitelist_pairs = self.dp.current_whitelist()
|
|
||||||
corr_pairs = self.config["freqai"]["feature_parameters"]["include_corr_pairlist"]
|
|
||||||
informative_pairs = []
|
|
||||||
for tf in self.config["freqai"]["feature_parameters"]["include_timeframes"]:
|
|
||||||
for pair in whitelist_pairs:
|
|
||||||
informative_pairs.append((pair, tf))
|
|
||||||
for pair in corr_pairs:
|
|
||||||
if pair in whitelist_pairs:
|
|
||||||
continue # avoid duplication
|
|
||||||
informative_pairs.append((pair, tf))
|
|
||||||
return informative_pairs
|
|
||||||
|
|
||||||
def populate_any_indicators(
|
def populate_any_indicators(
|
||||||
self, pair, df, tf, informative=None, set_generalized_indicators=False
|
self, pair, df, tf, informative=None, set_generalized_indicators=False
|
||||||
):
|
):
|
||||||
|
@ -43,19 +43,6 @@ class freqai_test_strat(IStrategy):
|
|||||||
)
|
)
|
||||||
max_roi_time_long = IntParameter(0, 800, default=400, space="sell", optimize=False, load=True)
|
max_roi_time_long = IntParameter(0, 800, default=400, space="sell", optimize=False, load=True)
|
||||||
|
|
||||||
def informative_pairs(self):
|
|
||||||
whitelist_pairs = self.dp.current_whitelist()
|
|
||||||
corr_pairs = self.config["freqai"]["feature_parameters"]["include_corr_pairlist"]
|
|
||||||
informative_pairs = []
|
|
||||||
for tf in self.config["freqai"]["feature_parameters"]["include_timeframes"]:
|
|
||||||
for pair in whitelist_pairs:
|
|
||||||
informative_pairs.append((pair, tf))
|
|
||||||
for pair in corr_pairs:
|
|
||||||
if pair in whitelist_pairs:
|
|
||||||
continue # avoid duplication
|
|
||||||
informative_pairs.append((pair, tf))
|
|
||||||
return informative_pairs
|
|
||||||
|
|
||||||
def populate_any_indicators(
|
def populate_any_indicators(
|
||||||
self, pair, df, tf, informative=None, set_generalized_indicators=False
|
self, pair, df, tf, informative=None, set_generalized_indicators=False
|
||||||
):
|
):
|
||||||
|
@ -1427,6 +1427,7 @@ def test_handle_stoploss_on_exchange_trailing(
|
|||||||
trade.is_open = True
|
trade.is_open = True
|
||||||
trade.open_order_id = None
|
trade.open_order_id = None
|
||||||
trade.stoploss_order_id = 100
|
trade.stoploss_order_id = 100
|
||||||
|
trade.stoploss_last_update = arrow.utcnow().shift(minutes=-20).datetime
|
||||||
|
|
||||||
stoploss_order_hanging = MagicMock(return_value={
|
stoploss_order_hanging = MagicMock(return_value={
|
||||||
'id': 100,
|
'id': 100,
|
||||||
@ -1456,7 +1457,7 @@ def test_handle_stoploss_on_exchange_trailing(
|
|||||||
)
|
)
|
||||||
|
|
||||||
cancel_order_mock = MagicMock()
|
cancel_order_mock = MagicMock()
|
||||||
stoploss_order_mock = MagicMock(return_value={'id': 13434334})
|
stoploss_order_mock = MagicMock(return_value={'id': 'so1'})
|
||||||
mocker.patch('freqtrade.exchange.Binance.cancel_stoploss_order', cancel_order_mock)
|
mocker.patch('freqtrade.exchange.Binance.cancel_stoploss_order', cancel_order_mock)
|
||||||
mocker.patch('freqtrade.exchange.Binance.stoploss', stoploss_order_mock)
|
mocker.patch('freqtrade.exchange.Binance.stoploss', stoploss_order_mock)
|
||||||
|
|
||||||
@ -1569,6 +1570,7 @@ def test_handle_stoploss_on_exchange_trailing_error(
|
|||||||
assert stoploss.call_count == 1
|
assert stoploss.call_count == 1
|
||||||
|
|
||||||
# Fail creating stoploss order
|
# Fail creating stoploss order
|
||||||
|
trade.stoploss_last_update = arrow.utcnow().shift(minutes=-601).datetime
|
||||||
caplog.clear()
|
caplog.clear()
|
||||||
cancel_mock = mocker.patch("freqtrade.exchange.Binance.cancel_stoploss_order", MagicMock())
|
cancel_mock = mocker.patch("freqtrade.exchange.Binance.cancel_stoploss_order", MagicMock())
|
||||||
mocker.patch("freqtrade.exchange.Binance.stoploss", side_effect=ExchangeError())
|
mocker.patch("freqtrade.exchange.Binance.stoploss", side_effect=ExchangeError())
|
||||||
@ -1657,6 +1659,7 @@ def test_handle_stoploss_on_exchange_custom_stop(
|
|||||||
trade.is_open = True
|
trade.is_open = True
|
||||||
trade.open_order_id = None
|
trade.open_order_id = None
|
||||||
trade.stoploss_order_id = 100
|
trade.stoploss_order_id = 100
|
||||||
|
trade.stoploss_last_update = arrow.utcnow().shift(minutes=-601).datetime
|
||||||
|
|
||||||
stoploss_order_hanging = MagicMock(return_value={
|
stoploss_order_hanging = MagicMock(return_value={
|
||||||
'id': 100,
|
'id': 100,
|
||||||
@ -1685,7 +1688,7 @@ def test_handle_stoploss_on_exchange_custom_stop(
|
|||||||
)
|
)
|
||||||
|
|
||||||
cancel_order_mock = MagicMock()
|
cancel_order_mock = MagicMock()
|
||||||
stoploss_order_mock = MagicMock(return_value={'id': 13434334})
|
stoploss_order_mock = MagicMock(return_value={'id': 'so1'})
|
||||||
mocker.patch('freqtrade.exchange.Binance.cancel_stoploss_order', cancel_order_mock)
|
mocker.patch('freqtrade.exchange.Binance.cancel_stoploss_order', cancel_order_mock)
|
||||||
mocker.patch('freqtrade.exchange.Binance.stoploss', stoploss_order_mock)
|
mocker.patch('freqtrade.exchange.Binance.stoploss', stoploss_order_mock)
|
||||||
|
|
||||||
@ -1727,8 +1730,7 @@ def test_handle_stoploss_on_exchange_custom_stop(
|
|||||||
assert freqtrade.handle_trade(trade) is True
|
assert freqtrade.handle_trade(trade) is True
|
||||||
|
|
||||||
|
|
||||||
def test_tsl_on_exchange_compatible_with_edge(mocker, edge_conf, fee, caplog,
|
def test_tsl_on_exchange_compatible_with_edge(mocker, edge_conf, fee, limit_order) -> None:
|
||||||
limit_order) -> None:
|
|
||||||
|
|
||||||
enter_order = limit_order['buy']
|
enter_order = limit_order['buy']
|
||||||
exit_order = limit_order['sell']
|
exit_order = limit_order['sell']
|
||||||
@ -1784,6 +1786,7 @@ def test_tsl_on_exchange_compatible_with_edge(mocker, edge_conf, fee, caplog,
|
|||||||
trade.is_open = True
|
trade.is_open = True
|
||||||
trade.open_order_id = None
|
trade.open_order_id = None
|
||||||
trade.stoploss_order_id = 100
|
trade.stoploss_order_id = 100
|
||||||
|
trade.stoploss_last_update = arrow.utcnow()
|
||||||
|
|
||||||
stoploss_order_hanging = MagicMock(return_value={
|
stoploss_order_hanging = MagicMock(return_value={
|
||||||
'id': 100,
|
'id': 100,
|
||||||
|
Loading…
Reference in New Issue
Block a user