revert constants.py and add changes
This commit is contained in:
parent
3020218096
commit
e9a7b68bc1
@ -8,133 +8,87 @@ from typing import List, Literal, Tuple
|
|||||||
from freqtrade.enums import CandleType
|
from freqtrade.enums import CandleType
|
||||||
|
|
||||||
|
|
||||||
DEFAULT_CONFIG = "config.json"
|
DEFAULT_CONFIG = 'config.json'
|
||||||
DEFAULT_EXCHANGE = "bittrex"
|
DEFAULT_EXCHANGE = 'bittrex'
|
||||||
PROCESS_THROTTLE_SECS = 5 # sec
|
PROCESS_THROTTLE_SECS = 5 # sec
|
||||||
HYPEROPT_EPOCH = 100 # epochs
|
HYPEROPT_EPOCH = 100 # epochs
|
||||||
RETRY_TIMEOUT = 30 # sec
|
RETRY_TIMEOUT = 30 # sec
|
||||||
TIMEOUT_UNITS = ["minutes", "seconds"]
|
TIMEOUT_UNITS = ['minutes', 'seconds']
|
||||||
EXPORT_OPTIONS = ["none", "trades", "signals"]
|
EXPORT_OPTIONS = ['none', 'trades', 'signals']
|
||||||
DEFAULT_DB_PROD_URL = "sqlite:///tradesv3.sqlite"
|
DEFAULT_DB_PROD_URL = 'sqlite:///tradesv3.sqlite'
|
||||||
DEFAULT_DB_DRYRUN_URL = "sqlite:///tradesv3.dryrun.sqlite"
|
DEFAULT_DB_DRYRUN_URL = 'sqlite:///tradesv3.dryrun.sqlite'
|
||||||
UNLIMITED_STAKE_AMOUNT = "unlimited"
|
UNLIMITED_STAKE_AMOUNT = 'unlimited'
|
||||||
DEFAULT_AMOUNT_RESERVE_PERCENT = 0.05
|
DEFAULT_AMOUNT_RESERVE_PERCENT = 0.05
|
||||||
REQUIRED_ORDERTIF = ["entry", "exit"]
|
REQUIRED_ORDERTIF = ['entry', 'exit']
|
||||||
REQUIRED_ORDERTYPES = ["entry", "exit", "stoploss", "stoploss_on_exchange"]
|
REQUIRED_ORDERTYPES = ['entry', 'exit', 'stoploss', 'stoploss_on_exchange']
|
||||||
PRICING_SIDES = ["ask", "bid", "same", "other"]
|
PRICING_SIDES = ['ask', 'bid', 'same', 'other']
|
||||||
ORDERTYPE_POSSIBILITIES = ["limit", "market"]
|
ORDERTYPE_POSSIBILITIES = ['limit', 'market']
|
||||||
ORDERTIF_POSSIBILITIES = ["gtc", "fok", "ioc"]
|
ORDERTIF_POSSIBILITIES = ['gtc', 'fok', 'ioc']
|
||||||
HYPEROPT_LOSS_BUILTIN = [
|
HYPEROPT_LOSS_BUILTIN = ['ShortTradeDurHyperOptLoss', 'OnlyProfitHyperOptLoss',
|
||||||
"ShortTradeDurHyperOptLoss",
|
'SharpeHyperOptLoss', 'SharpeHyperOptLossDaily',
|
||||||
"OnlyProfitHyperOptLoss",
|
'SortinoHyperOptLoss', 'SortinoHyperOptLossDaily',
|
||||||
"SharpeHyperOptLoss",
|
'CalmarHyperOptLoss',
|
||||||
"SharpeHyperOptLossDaily",
|
'MaxDrawDownHyperOptLoss', 'MaxDrawDownRelativeHyperOptLoss',
|
||||||
"SortinoHyperOptLoss",
|
'ProfitDrawDownHyperOptLoss']
|
||||||
"SortinoHyperOptLossDaily",
|
AVAILABLE_PAIRLISTS = ['StaticPairList', 'VolumePairList',
|
||||||
"CalmarHyperOptLoss",
|
'AgeFilter', 'OffsetFilter', 'PerformanceFilter',
|
||||||
"MaxDrawDownHyperOptLoss",
|
'PrecisionFilter', 'PriceFilter', 'RangeStabilityFilter',
|
||||||
"MaxDrawDownRelativeHyperOptLoss",
|
'ShuffleFilter', 'SpreadFilter', 'VolatilityFilter']
|
||||||
"ProfitDrawDownHyperOptLoss",
|
AVAILABLE_PROTECTIONS = ['CooldownPeriod', 'LowProfitPairs', 'MaxDrawdown', 'StoplossGuard']
|
||||||
]
|
AVAILABLE_DATAHANDLERS = ['json', 'jsongz', 'hdf5']
|
||||||
AVAILABLE_PAIRLISTS = [
|
BACKTEST_BREAKDOWNS = ['day', 'week', 'month']
|
||||||
"StaticPairList",
|
BACKTEST_CACHE_AGE = ['none', 'day', 'week', 'month']
|
||||||
"VolumePairList",
|
BACKTEST_CACHE_DEFAULT = 'day'
|
||||||
"AgeFilter",
|
|
||||||
"OffsetFilter",
|
|
||||||
"PerformanceFilter",
|
|
||||||
"PrecisionFilter",
|
|
||||||
"PriceFilter",
|
|
||||||
"RangeStabilityFilter",
|
|
||||||
"ShuffleFilter",
|
|
||||||
"SpreadFilter",
|
|
||||||
"VolatilityFilter",
|
|
||||||
]
|
|
||||||
AVAILABLE_PROTECTIONS = ["CooldownPeriod", "LowProfitPairs", "MaxDrawdown", "StoplossGuard"]
|
|
||||||
AVAILABLE_DATAHANDLERS = ["json", "jsongz", "hdf5"]
|
|
||||||
BACKTEST_BREAKDOWNS = ["day", "week", "month"]
|
|
||||||
BACKTEST_CACHE_AGE = ["none", "day", "week", "month"]
|
|
||||||
BACKTEST_CACHE_DEFAULT = "day"
|
|
||||||
DRY_RUN_WALLET = 1000
|
DRY_RUN_WALLET = 1000
|
||||||
DATETIME_PRINT_FORMAT = "%Y-%m-%d %H:%M:%S"
|
DATETIME_PRINT_FORMAT = '%Y-%m-%d %H:%M:%S'
|
||||||
MATH_CLOSE_PREC = 1e-14 # Precision used for float comparisons
|
MATH_CLOSE_PREC = 1e-14 # Precision used for float comparisons
|
||||||
DEFAULT_DATAFRAME_COLUMNS = ["date", "open", "high", "low", "close", "volume"]
|
DEFAULT_DATAFRAME_COLUMNS = ['date', 'open', 'high', 'low', 'close', 'volume']
|
||||||
# Don't modify sequence of DEFAULT_TRADES_COLUMNS
|
# Don't modify sequence of DEFAULT_TRADES_COLUMNS
|
||||||
# it has wide consequences for stored trades files
|
# it has wide consequences for stored trades files
|
||||||
DEFAULT_TRADES_COLUMNS = ["timestamp", "id", "type", "side", "price", "amount", "cost"]
|
DEFAULT_TRADES_COLUMNS = ['timestamp', 'id', 'type', 'side', 'price', 'amount', 'cost']
|
||||||
TRADING_MODES = ["spot", "margin", "futures"]
|
TRADING_MODES = ['spot', 'margin', 'futures']
|
||||||
MARGIN_MODES = ["cross", "isolated", ""]
|
MARGIN_MODES = ['cross', 'isolated', '']
|
||||||
|
|
||||||
LAST_BT_RESULT_FN = ".last_result.json"
|
LAST_BT_RESULT_FN = '.last_result.json'
|
||||||
FTHYPT_FILEVERSION = "fthypt_fileversion"
|
FTHYPT_FILEVERSION = 'fthypt_fileversion'
|
||||||
|
|
||||||
USERPATH_HYPEROPTS = "hyperopts"
|
USERPATH_HYPEROPTS = 'hyperopts'
|
||||||
USERPATH_STRATEGIES = "strategies"
|
USERPATH_STRATEGIES = 'strategies'
|
||||||
USERPATH_NOTEBOOKS = "notebooks"
|
USERPATH_NOTEBOOKS = 'notebooks'
|
||||||
USERPATH_FREQAIMODELS = "freqaimodels"
|
|
||||||
|
|
||||||
TELEGRAM_SETTING_OPTIONS = ["on", "off", "silent"]
|
TELEGRAM_SETTING_OPTIONS = ['on', 'off', 'silent']
|
||||||
WEBHOOK_FORMAT_OPTIONS = ["form", "json", "raw"]
|
WEBHOOK_FORMAT_OPTIONS = ['form', 'json', 'raw']
|
||||||
|
|
||||||
ENV_VAR_PREFIX = "FREQTRADE__"
|
ENV_VAR_PREFIX = 'FREQTRADE__'
|
||||||
|
|
||||||
NON_OPEN_EXCHANGE_STATES = ("cancelled", "canceled", "closed", "expired")
|
NON_OPEN_EXCHANGE_STATES = ('cancelled', 'canceled', 'closed', 'expired')
|
||||||
|
|
||||||
# Define decimals per coin for outputs
|
# Define decimals per coin for outputs
|
||||||
# Only used for outputs.
|
# Only used for outputs.
|
||||||
DECIMAL_PER_COIN_FALLBACK = 3 # Should be low to avoid listing all possible FIAT's
|
DECIMAL_PER_COIN_FALLBACK = 3 # Should be low to avoid listing all possible FIAT's
|
||||||
DECIMALS_PER_COIN = {
|
DECIMALS_PER_COIN = {
|
||||||
"BTC": 8,
|
'BTC': 8,
|
||||||
"ETH": 5,
|
'ETH': 5,
|
||||||
}
|
}
|
||||||
|
|
||||||
DUST_PER_COIN = {"BTC": 0.0001, "ETH": 0.01}
|
DUST_PER_COIN = {
|
||||||
|
'BTC': 0.0001,
|
||||||
|
'ETH': 0.01
|
||||||
|
}
|
||||||
|
|
||||||
# Source files with destination directories within user-directory
|
# Source files with destination directories within user-directory
|
||||||
USER_DATA_FILES = {
|
USER_DATA_FILES = {
|
||||||
"sample_strategy.py": USERPATH_STRATEGIES,
|
'sample_strategy.py': USERPATH_STRATEGIES,
|
||||||
"sample_hyperopt_loss.py": USERPATH_HYPEROPTS,
|
'sample_hyperopt_loss.py': USERPATH_HYPEROPTS,
|
||||||
"strategy_analysis_example.ipynb": USERPATH_NOTEBOOKS,
|
'strategy_analysis_example.ipynb': USERPATH_NOTEBOOKS,
|
||||||
}
|
}
|
||||||
|
|
||||||
SUPPORTED_FIAT = [
|
SUPPORTED_FIAT = [
|
||||||
"AUD",
|
"AUD", "BRL", "CAD", "CHF", "CLP", "CNY", "CZK", "DKK",
|
||||||
"BRL",
|
"EUR", "GBP", "HKD", "HUF", "IDR", "ILS", "INR", "JPY",
|
||||||
"CAD",
|
"KRW", "MXN", "MYR", "NOK", "NZD", "PHP", "PKR", "PLN",
|
||||||
"CHF",
|
"RUB", "UAH", "SEK", "SGD", "THB", "TRY", "TWD", "ZAR",
|
||||||
"CLP",
|
"USD", "BTC", "ETH", "XRP", "LTC", "BCH"
|
||||||
"CNY",
|
|
||||||
"CZK",
|
|
||||||
"DKK",
|
|
||||||
"EUR",
|
|
||||||
"GBP",
|
|
||||||
"HKD",
|
|
||||||
"HUF",
|
|
||||||
"IDR",
|
|
||||||
"ILS",
|
|
||||||
"INR",
|
|
||||||
"JPY",
|
|
||||||
"KRW",
|
|
||||||
"MXN",
|
|
||||||
"MYR",
|
|
||||||
"NOK",
|
|
||||||
"NZD",
|
|
||||||
"PHP",
|
|
||||||
"PKR",
|
|
||||||
"PLN",
|
|
||||||
"RUB",
|
|
||||||
"UAH",
|
|
||||||
"SEK",
|
|
||||||
"SGD",
|
|
||||||
"THB",
|
|
||||||
"TRY",
|
|
||||||
"TWD",
|
|
||||||
"ZAR",
|
|
||||||
"USD",
|
|
||||||
"BTC",
|
|
||||||
"ETH",
|
|
||||||
"XRP",
|
|
||||||
"LTC",
|
|
||||||
"BCH",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
MINIMAL_CONFIG = {
|
MINIMAL_CONFIG = {
|
||||||
@ -145,334 +99,338 @@ MINIMAL_CONFIG = {
|
|||||||
"key": "",
|
"key": "",
|
||||||
"secret": "",
|
"secret": "",
|
||||||
"pair_whitelist": [],
|
"pair_whitelist": [],
|
||||||
"ccxt_async_config": {},
|
"ccxt_async_config": {
|
||||||
},
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
# Required json-schema for user specified config
|
# Required json-schema for user specified config
|
||||||
CONF_SCHEMA = {
|
CONF_SCHEMA = {
|
||||||
"type": "object",
|
'type': 'object',
|
||||||
"properties": {
|
'properties': {
|
||||||
"max_open_trades": {"type": ["integer", "number"], "minimum": -1},
|
'max_open_trades': {'type': ['integer', 'number'], 'minimum': -1},
|
||||||
"new_pairs_days": {"type": "integer", "default": 30},
|
'new_pairs_days': {'type': 'integer', 'default': 30},
|
||||||
"timeframe": {"type": "string"},
|
'timeframe': {'type': 'string'},
|
||||||
"stake_currency": {"type": "string"},
|
'stake_currency': {'type': 'string'},
|
||||||
"stake_amount": {
|
'stake_amount': {
|
||||||
"type": ["number", "string"],
|
'type': ['number', 'string'],
|
||||||
"minimum": 0.0001,
|
'minimum': 0.0001,
|
||||||
"pattern": UNLIMITED_STAKE_AMOUNT,
|
'pattern': UNLIMITED_STAKE_AMOUNT
|
||||||
},
|
},
|
||||||
"tradable_balance_ratio": {"type": "number", "minimum": 0.0, "maximum": 1, "default": 0.99},
|
'tradable_balance_ratio': {
|
||||||
"available_capital": {
|
'type': 'number',
|
||||||
"type": "number",
|
'minimum': 0.0,
|
||||||
"minimum": 0,
|
'maximum': 1,
|
||||||
|
'default': 0.99
|
||||||
},
|
},
|
||||||
"amend_last_stake_amount": {"type": "boolean", "default": False},
|
'available_capital': {
|
||||||
"last_stake_amount_min_ratio": {
|
'type': 'number',
|
||||||
"type": "number",
|
'minimum': 0,
|
||||||
"minimum": 0.0,
|
|
||||||
"maximum": 1.0,
|
|
||||||
"default": 0.5,
|
|
||||||
},
|
},
|
||||||
"fiat_display_currency": {"type": "string", "enum": SUPPORTED_FIAT},
|
'amend_last_stake_amount': {'type': 'boolean', 'default': False},
|
||||||
"dry_run": {"type": "boolean"},
|
'last_stake_amount_min_ratio': {
|
||||||
"dry_run_wallet": {"type": "number", "default": DRY_RUN_WALLET},
|
'type': 'number', 'minimum': 0.0, 'maximum': 1.0, 'default': 0.5
|
||||||
"cancel_open_orders_on_exit": {"type": "boolean", "default": False},
|
|
||||||
"process_only_new_candles": {"type": "boolean"},
|
|
||||||
"minimal_roi": {
|
|
||||||
"type": "object",
|
|
||||||
"patternProperties": {"^[0-9.]+$": {"type": "number"}},
|
|
||||||
"minProperties": 1,
|
|
||||||
},
|
},
|
||||||
"amount_reserve_percent": {"type": "number", "minimum": 0.0, "maximum": 0.5},
|
'fiat_display_currency': {'type': 'string', 'enum': SUPPORTED_FIAT},
|
||||||
"stoploss": {"type": "number", "maximum": 0, "exclusiveMaximum": True, "minimum": -1},
|
'dry_run': {'type': 'boolean'},
|
||||||
"trailing_stop": {"type": "boolean"},
|
'dry_run_wallet': {'type': 'number', 'default': DRY_RUN_WALLET},
|
||||||
"trailing_stop_positive": {"type": "number", "minimum": 0, "maximum": 1},
|
'cancel_open_orders_on_exit': {'type': 'boolean', 'default': False},
|
||||||
"trailing_stop_positive_offset": {"type": "number", "minimum": 0, "maximum": 1},
|
'process_only_new_candles': {'type': 'boolean'},
|
||||||
"trailing_only_offset_is_reached": {"type": "boolean"},
|
'minimal_roi': {
|
||||||
"use_exit_signal": {"type": "boolean"},
|
'type': 'object',
|
||||||
"exit_profit_only": {"type": "boolean"},
|
'patternProperties': {
|
||||||
"exit_profit_offset": {"type": "number"},
|
'^[0-9.]+$': {'type': 'number'}
|
||||||
"ignore_roi_if_entry_signal": {"type": "boolean"},
|
|
||||||
"ignore_buying_expired_candle_after": {"type": "number"},
|
|
||||||
"trading_mode": {"type": "string", "enum": TRADING_MODES},
|
|
||||||
"margin_mode": {"type": "string", "enum": MARGIN_MODES},
|
|
||||||
"liquidation_buffer": {"type": "number", "minimum": 0.0, "maximum": 0.99},
|
|
||||||
"backtest_breakdown": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {"type": "string", "enum": BACKTEST_BREAKDOWNS},
|
|
||||||
},
|
},
|
||||||
"bot_name": {"type": "string"},
|
'minProperties': 1
|
||||||
"unfilledtimeout": {
|
},
|
||||||
"type": "object",
|
'amount_reserve_percent': {'type': 'number', 'minimum': 0.0, 'maximum': 0.5},
|
||||||
"properties": {
|
'stoploss': {'type': 'number', 'maximum': 0, 'exclusiveMaximum': True, 'minimum': -1},
|
||||||
"entry": {"type": "number", "minimum": 1},
|
'trailing_stop': {'type': 'boolean'},
|
||||||
"exit": {"type": "number", "minimum": 1},
|
'trailing_stop_positive': {'type': 'number', 'minimum': 0, 'maximum': 1},
|
||||||
"exit_timeout_count": {"type": "number", "minimum": 0, "default": 0},
|
'trailing_stop_positive_offset': {'type': 'number', 'minimum': 0, 'maximum': 1},
|
||||||
"unit": {"type": "string", "enum": TIMEOUT_UNITS, "default": "minutes"},
|
'trailing_only_offset_is_reached': {'type': 'boolean'},
|
||||||
|
'use_exit_signal': {'type': 'boolean'},
|
||||||
|
'exit_profit_only': {'type': 'boolean'},
|
||||||
|
'exit_profit_offset': {'type': 'number'},
|
||||||
|
'ignore_roi_if_entry_signal': {'type': 'boolean'},
|
||||||
|
'ignore_buying_expired_candle_after': {'type': 'number'},
|
||||||
|
'trading_mode': {'type': 'string', 'enum': TRADING_MODES},
|
||||||
|
'margin_mode': {'type': 'string', 'enum': MARGIN_MODES},
|
||||||
|
'liquidation_buffer': {'type': 'number', 'minimum': 0.0, 'maximum': 0.99},
|
||||||
|
'backtest_breakdown': {
|
||||||
|
'type': 'array',
|
||||||
|
'items': {'type': 'string', 'enum': BACKTEST_BREAKDOWNS}
|
||||||
|
},
|
||||||
|
'bot_name': {'type': 'string'},
|
||||||
|
'unfilledtimeout': {
|
||||||
|
'type': 'object',
|
||||||
|
'properties': {
|
||||||
|
'entry': {'type': 'number', 'minimum': 1},
|
||||||
|
'exit': {'type': 'number', 'minimum': 1},
|
||||||
|
'exit_timeout_count': {'type': 'number', 'minimum': 0, 'default': 0},
|
||||||
|
'unit': {'type': 'string', 'enum': TIMEOUT_UNITS, 'default': 'minutes'}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'entry_pricing': {
|
||||||
|
'type': 'object',
|
||||||
|
'properties': {
|
||||||
|
'price_last_balance': {
|
||||||
|
'type': 'number',
|
||||||
|
'minimum': 0,
|
||||||
|
'maximum': 1,
|
||||||
|
'exclusiveMaximum': False,
|
||||||
|
},
|
||||||
|
'price_side': {'type': 'string', 'enum': PRICING_SIDES, 'default': 'same'},
|
||||||
|
'use_order_book': {'type': 'boolean'},
|
||||||
|
'order_book_top': {'type': 'integer', 'minimum': 1, 'maximum': 50, },
|
||||||
|
'check_depth_of_market': {
|
||||||
|
'type': 'object',
|
||||||
|
'properties': {
|
||||||
|
'enabled': {'type': 'boolean'},
|
||||||
|
'bids_to_ask_delta': {'type': 'number', 'minimum': 0},
|
||||||
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"entry_pricing": {
|
'required': ['price_side']
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"price_last_balance": {
|
|
||||||
"type": "number",
|
|
||||||
"minimum": 0,
|
|
||||||
"maximum": 1,
|
|
||||||
"exclusiveMaximum": False,
|
|
||||||
},
|
},
|
||||||
"price_side": {"type": "string", "enum": PRICING_SIDES, "default": "same"},
|
'exit_pricing': {
|
||||||
"use_order_book": {"type": "boolean"},
|
'type': 'object',
|
||||||
"order_book_top": {
|
'properties': {
|
||||||
"type": "integer",
|
'price_side': {'type': 'string', 'enum': PRICING_SIDES, 'default': 'same'},
|
||||||
"minimum": 1,
|
'price_last_balance': {
|
||||||
"maximum": 50,
|
'type': 'number',
|
||||||
|
'minimum': 0,
|
||||||
|
'maximum': 1,
|
||||||
|
'exclusiveMaximum': False,
|
||||||
},
|
},
|
||||||
"check_depth_of_market": {
|
'use_order_book': {'type': 'boolean'},
|
||||||
"type": "object",
|
'order_book_top': {'type': 'integer', 'minimum': 1, 'maximum': 50, },
|
||||||
"properties": {
|
},
|
||||||
"enabled": {"type": "boolean"},
|
'required': ['price_side']
|
||||||
"bids_to_ask_delta": {"type": "number", "minimum": 0},
|
},
|
||||||
|
'custom_price_max_distance_ratio': {
|
||||||
|
'type': 'number', 'minimum': 0.0
|
||||||
|
},
|
||||||
|
'order_types': {
|
||||||
|
'type': 'object',
|
||||||
|
'properties': {
|
||||||
|
'entry': {'type': 'string', 'enum': ORDERTYPE_POSSIBILITIES},
|
||||||
|
'exit': {'type': 'string', 'enum': ORDERTYPE_POSSIBILITIES},
|
||||||
|
'force_exit': {'type': 'string', 'enum': ORDERTYPE_POSSIBILITIES},
|
||||||
|
'force_entry': {'type': 'string', 'enum': ORDERTYPE_POSSIBILITIES},
|
||||||
|
'emergency_exit': {
|
||||||
|
'type': 'string',
|
||||||
|
'enum': ORDERTYPE_POSSIBILITIES,
|
||||||
|
'default': 'market'},
|
||||||
|
'stoploss': {'type': 'string', 'enum': ORDERTYPE_POSSIBILITIES},
|
||||||
|
'stoploss_on_exchange': {'type': 'boolean'},
|
||||||
|
'stoploss_on_exchange_interval': {'type': 'number'},
|
||||||
|
'stoploss_on_exchange_limit_ratio': {'type': 'number', 'minimum': 0.0,
|
||||||
|
'maximum': 1.0}
|
||||||
|
},
|
||||||
|
'required': ['entry', 'exit', 'stoploss', 'stoploss_on_exchange']
|
||||||
|
},
|
||||||
|
'order_time_in_force': {
|
||||||
|
'type': 'object',
|
||||||
|
'properties': {
|
||||||
|
'entry': {'type': 'string', 'enum': ORDERTIF_POSSIBILITIES},
|
||||||
|
'exit': {'type': 'string', 'enum': ORDERTIF_POSSIBILITIES}
|
||||||
|
},
|
||||||
|
'required': REQUIRED_ORDERTIF
|
||||||
|
},
|
||||||
|
'exchange': {'$ref': '#/definitions/exchange'},
|
||||||
|
'edge': {'$ref': '#/definitions/edge'},
|
||||||
|
'experimental': {
|
||||||
|
'type': 'object',
|
||||||
|
'properties': {
|
||||||
|
'block_bad_exchanges': {'type': 'boolean'}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'pairlists': {
|
||||||
|
'type': 'array',
|
||||||
|
'items': {
|
||||||
|
'type': 'object',
|
||||||
|
'properties': {
|
||||||
|
'method': {'type': 'string', 'enum': AVAILABLE_PAIRLISTS},
|
||||||
|
},
|
||||||
|
'required': ['method'],
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'protections': {
|
||||||
|
'type': 'array',
|
||||||
|
'items': {
|
||||||
|
'type': 'object',
|
||||||
|
'properties': {
|
||||||
|
'method': {'type': 'string', 'enum': AVAILABLE_PROTECTIONS},
|
||||||
|
'stop_duration': {'type': 'number', 'minimum': 0.0},
|
||||||
|
'stop_duration_candles': {'type': 'number', 'minimum': 0},
|
||||||
|
'trade_limit': {'type': 'number', 'minimum': 1},
|
||||||
|
'lookback_period': {'type': 'number', 'minimum': 1},
|
||||||
|
'lookback_period_candles': {'type': 'number', 'minimum': 1},
|
||||||
|
},
|
||||||
|
'required': ['method'],
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'telegram': {
|
||||||
|
'type': 'object',
|
||||||
|
'properties': {
|
||||||
|
'enabled': {'type': 'boolean'},
|
||||||
|
'token': {'type': 'string'},
|
||||||
|
'chat_id': {'type': 'string'},
|
||||||
|
'balance_dust_level': {'type': 'number', 'minimum': 0.0},
|
||||||
|
'notification_settings': {
|
||||||
|
'type': 'object',
|
||||||
|
'default': {},
|
||||||
|
'properties': {
|
||||||
|
'status': {'type': 'string', 'enum': TELEGRAM_SETTING_OPTIONS},
|
||||||
|
'warning': {'type': 'string', 'enum': TELEGRAM_SETTING_OPTIONS},
|
||||||
|
'startup': {'type': 'string', 'enum': TELEGRAM_SETTING_OPTIONS},
|
||||||
|
'entry': {'type': 'string', 'enum': TELEGRAM_SETTING_OPTIONS},
|
||||||
|
'entry_cancel': {'type': 'string', 'enum': TELEGRAM_SETTING_OPTIONS},
|
||||||
|
'entry_fill': {'type': 'string',
|
||||||
|
'enum': TELEGRAM_SETTING_OPTIONS,
|
||||||
|
'default': 'off'
|
||||||
|
},
|
||||||
|
'exit': {
|
||||||
|
'type': ['string', 'object'],
|
||||||
|
'additionalProperties': {
|
||||||
|
'type': 'string',
|
||||||
|
'enum': TELEGRAM_SETTING_OPTIONS
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'exit_cancel': {'type': 'string', 'enum': TELEGRAM_SETTING_OPTIONS},
|
||||||
|
'exit_fill': {
|
||||||
|
'type': 'string',
|
||||||
|
'enum': TELEGRAM_SETTING_OPTIONS,
|
||||||
|
'default': 'off'
|
||||||
|
},
|
||||||
|
'protection_trigger': {
|
||||||
|
'type': 'string',
|
||||||
|
'enum': TELEGRAM_SETTING_OPTIONS,
|
||||||
|
'default': 'off'
|
||||||
|
},
|
||||||
|
'protection_trigger_global': {
|
||||||
|
'type': 'string',
|
||||||
|
'enum': TELEGRAM_SETTING_OPTIONS,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'reload': {'type': 'boolean'},
|
||||||
|
},
|
||||||
|
'required': ['enabled', 'token', 'chat_id'],
|
||||||
|
},
|
||||||
|
'webhook': {
|
||||||
|
'type': 'object',
|
||||||
|
'properties': {
|
||||||
|
'enabled': {'type': 'boolean'},
|
||||||
|
'url': {'type': 'string'},
|
||||||
|
'format': {'type': 'string', 'enum': WEBHOOK_FORMAT_OPTIONS, 'default': 'form'},
|
||||||
|
'retries': {'type': 'integer', 'minimum': 0},
|
||||||
|
'retry_delay': {'type': 'number', 'minimum': 0},
|
||||||
|
'webhookentry': {'type': 'object'},
|
||||||
|
'webhookentrycancel': {'type': 'object'},
|
||||||
|
'webhookentryfill': {'type': 'object'},
|
||||||
|
'webhookexit': {'type': 'object'},
|
||||||
|
'webhookexitcancel': {'type': 'object'},
|
||||||
|
'webhookexitfill': {'type': 'object'},
|
||||||
|
'webhookstatus': {'type': 'object'},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
'api_server': {
|
||||||
|
'type': 'object',
|
||||||
|
'properties': {
|
||||||
|
'enabled': {'type': 'boolean'},
|
||||||
|
'listen_ip_address': {'format': 'ipv4'},
|
||||||
|
'listen_port': {
|
||||||
|
'type': 'integer',
|
||||||
|
'minimum': 1024,
|
||||||
|
'maximum': 65535
|
||||||
},
|
},
|
||||||
"required": ["price_side"],
|
'username': {'type': 'string'},
|
||||||
|
'password': {'type': 'string'},
|
||||||
|
'jwt_secret_key': {'type': 'string'},
|
||||||
|
'CORS_origins': {'type': 'array', 'items': {'type': 'string'}},
|
||||||
|
'verbosity': {'type': 'string', 'enum': ['error', 'info']},
|
||||||
},
|
},
|
||||||
"exit_pricing": {
|
'required': ['enabled', 'listen_ip_address', 'listen_port', 'username', 'password']
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"price_side": {"type": "string", "enum": PRICING_SIDES, "default": "same"},
|
|
||||||
"price_last_balance": {
|
|
||||||
"type": "number",
|
|
||||||
"minimum": 0,
|
|
||||||
"maximum": 1,
|
|
||||||
"exclusiveMaximum": False,
|
|
||||||
},
|
},
|
||||||
"use_order_book": {"type": "boolean"},
|
'db_url': {'type': 'string'},
|
||||||
"order_book_top": {
|
'export': {'type': 'string', 'enum': EXPORT_OPTIONS, 'default': 'trades'},
|
||||||
"type": "integer",
|
'disableparamexport': {'type': 'boolean'},
|
||||||
"minimum": 1,
|
'initial_state': {'type': 'string', 'enum': ['running', 'stopped']},
|
||||||
"maximum": 50,
|
'force_entry_enable': {'type': 'boolean'},
|
||||||
|
'disable_dataframe_checks': {'type': 'boolean'},
|
||||||
|
'internals': {
|
||||||
|
'type': 'object',
|
||||||
|
'default': {},
|
||||||
|
'properties': {
|
||||||
|
'process_throttle_secs': {'type': 'integer'},
|
||||||
|
'interval': {'type': 'integer'},
|
||||||
|
'sd_notify': {'type': 'boolean'},
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
'dataformat_ohlcv': {
|
||||||
|
'type': 'string',
|
||||||
|
'enum': AVAILABLE_DATAHANDLERS,
|
||||||
|
'default': 'json'
|
||||||
},
|
},
|
||||||
"required": ["price_side"],
|
'dataformat_trades': {
|
||||||
|
'type': 'string',
|
||||||
|
'enum': AVAILABLE_DATAHANDLERS,
|
||||||
|
'default': 'jsongz'
|
||||||
},
|
},
|
||||||
"custom_price_max_distance_ratio": {"type": "number", "minimum": 0.0},
|
'position_adjustment_enable': {'type': 'boolean'},
|
||||||
"order_types": {
|
'max_entry_position_adjustment': {'type': ['integer', 'number'], 'minimum': -1},
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"entry": {"type": "string", "enum": ORDERTYPE_POSSIBILITIES},
|
|
||||||
"exit": {"type": "string", "enum": ORDERTYPE_POSSIBILITIES},
|
|
||||||
"force_exit": {"type": "string", "enum": ORDERTYPE_POSSIBILITIES},
|
|
||||||
"force_entry": {"type": "string", "enum": ORDERTYPE_POSSIBILITIES},
|
|
||||||
"emergency_exit": {
|
|
||||||
"type": "string",
|
|
||||||
"enum": ORDERTYPE_POSSIBILITIES,
|
|
||||||
"default": "market",
|
|
||||||
},
|
},
|
||||||
"stoploss": {"type": "string", "enum": ORDERTYPE_POSSIBILITIES},
|
'definitions': {
|
||||||
"stoploss_on_exchange": {"type": "boolean"},
|
'exchange': {
|
||||||
"stoploss_on_exchange_interval": {"type": "number"},
|
'type': 'object',
|
||||||
"stoploss_on_exchange_limit_ratio": {
|
'properties': {
|
||||||
"type": "number",
|
'name': {'type': 'string'},
|
||||||
"minimum": 0.0,
|
'sandbox': {'type': 'boolean', 'default': False},
|
||||||
"maximum": 1.0,
|
'key': {'type': 'string', 'default': ''},
|
||||||
|
'secret': {'type': 'string', 'default': ''},
|
||||||
|
'password': {'type': 'string', 'default': ''},
|
||||||
|
'uid': {'type': 'string'},
|
||||||
|
'pair_whitelist': {
|
||||||
|
'type': 'array',
|
||||||
|
'items': {
|
||||||
|
'type': 'string',
|
||||||
},
|
},
|
||||||
|
'uniqueItems': True
|
||||||
},
|
},
|
||||||
"required": ["entry", "exit", "stoploss", "stoploss_on_exchange"],
|
'pair_blacklist': {
|
||||||
|
'type': 'array',
|
||||||
|
'items': {
|
||||||
|
'type': 'string',
|
||||||
},
|
},
|
||||||
"order_time_in_force": {
|
'uniqueItems': True
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"entry": {"type": "string", "enum": ORDERTIF_POSSIBILITIES},
|
|
||||||
"exit": {"type": "string", "enum": ORDERTIF_POSSIBILITIES},
|
|
||||||
},
|
},
|
||||||
"required": REQUIRED_ORDERTIF,
|
'unknown_fee_rate': {'type': 'number'},
|
||||||
|
'outdated_offset': {'type': 'integer', 'minimum': 1},
|
||||||
|
'markets_refresh_interval': {'type': 'integer'},
|
||||||
|
'ccxt_config': {'type': 'object'},
|
||||||
|
'ccxt_async_config': {'type': 'object'}
|
||||||
},
|
},
|
||||||
"exchange": {"$ref": "#/definitions/exchange"},
|
'required': ['name']
|
||||||
"edge": {"$ref": "#/definitions/edge"},
|
|
||||||
"experimental": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {"block_bad_exchanges": {"type": "boolean"}},
|
|
||||||
},
|
},
|
||||||
"pairlists": {
|
'edge': {
|
||||||
"type": "array",
|
'type': 'object',
|
||||||
"items": {
|
'properties': {
|
||||||
"type": "object",
|
'enabled': {'type': 'boolean'},
|
||||||
"properties": {
|
'process_throttle_secs': {'type': 'integer', 'minimum': 600},
|
||||||
"method": {"type": "string", "enum": AVAILABLE_PAIRLISTS},
|
'calculate_since_number_of_days': {'type': 'integer'},
|
||||||
|
'allowed_risk': {'type': 'number'},
|
||||||
|
'stoploss_range_min': {'type': 'number'},
|
||||||
|
'stoploss_range_max': {'type': 'number'},
|
||||||
|
'stoploss_range_step': {'type': 'number'},
|
||||||
|
'minimum_winrate': {'type': 'number'},
|
||||||
|
'minimum_expectancy': {'type': 'number'},
|
||||||
|
'min_trade_number': {'type': 'number'},
|
||||||
|
'max_trade_duration_minute': {'type': 'integer'},
|
||||||
|
'remove_pumps': {'type': 'boolean'}
|
||||||
},
|
},
|
||||||
"required": ["method"],
|
'required': ['process_throttle_secs', 'allowed_risk']
|
||||||
},
|
|
||||||
},
|
|
||||||
"protections": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"method": {"type": "string", "enum": AVAILABLE_PROTECTIONS},
|
|
||||||
"stop_duration": {"type": "number", "minimum": 0.0},
|
|
||||||
"stop_duration_candles": {"type": "number", "minimum": 0},
|
|
||||||
"trade_limit": {"type": "number", "minimum": 1},
|
|
||||||
"lookback_period": {"type": "number", "minimum": 1},
|
|
||||||
"lookback_period_candles": {"type": "number", "minimum": 1},
|
|
||||||
},
|
|
||||||
"required": ["method"],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"telegram": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"enabled": {"type": "boolean"},
|
|
||||||
"token": {"type": "string"},
|
|
||||||
"chat_id": {"type": "string"},
|
|
||||||
"balance_dust_level": {"type": "number", "minimum": 0.0},
|
|
||||||
"notification_settings": {
|
|
||||||
"type": "object",
|
|
||||||
"default": {},
|
|
||||||
"properties": {
|
|
||||||
"status": {"type": "string", "enum": TELEGRAM_SETTING_OPTIONS},
|
|
||||||
"warning": {"type": "string", "enum": TELEGRAM_SETTING_OPTIONS},
|
|
||||||
"startup": {"type": "string", "enum": TELEGRAM_SETTING_OPTIONS},
|
|
||||||
"entry": {"type": "string", "enum": TELEGRAM_SETTING_OPTIONS},
|
|
||||||
"entry_cancel": {"type": "string", "enum": TELEGRAM_SETTING_OPTIONS},
|
|
||||||
"entry_fill": {
|
|
||||||
"type": "string",
|
|
||||||
"enum": TELEGRAM_SETTING_OPTIONS,
|
|
||||||
"default": "off",
|
|
||||||
},
|
|
||||||
"exit": {
|
|
||||||
"type": ["string", "object"],
|
|
||||||
"additionalProperties": {
|
|
||||||
"type": "string",
|
|
||||||
"enum": TELEGRAM_SETTING_OPTIONS,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"exit_cancel": {"type": "string", "enum": TELEGRAM_SETTING_OPTIONS},
|
|
||||||
"exit_fill": {
|
|
||||||
"type": "string",
|
|
||||||
"enum": TELEGRAM_SETTING_OPTIONS,
|
|
||||||
"default": "off",
|
|
||||||
},
|
|
||||||
"protection_trigger": {
|
|
||||||
"type": "string",
|
|
||||||
"enum": TELEGRAM_SETTING_OPTIONS,
|
|
||||||
"default": "off",
|
|
||||||
},
|
|
||||||
"protection_trigger_global": {
|
|
||||||
"type": "string",
|
|
||||||
"enum": TELEGRAM_SETTING_OPTIONS,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"reload": {"type": "boolean"},
|
|
||||||
},
|
|
||||||
"required": ["enabled", "token", "chat_id"],
|
|
||||||
},
|
|
||||||
"webhook": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"enabled": {"type": "boolean"},
|
|
||||||
"url": {"type": "string"},
|
|
||||||
"format": {"type": "string", "enum": WEBHOOK_FORMAT_OPTIONS, "default": "form"},
|
|
||||||
"retries": {"type": "integer", "minimum": 0},
|
|
||||||
"retry_delay": {"type": "number", "minimum": 0},
|
|
||||||
"webhookentry": {"type": "object"},
|
|
||||||
"webhookentrycancel": {"type": "object"},
|
|
||||||
"webhookentryfill": {"type": "object"},
|
|
||||||
"webhookexit": {"type": "object"},
|
|
||||||
"webhookexitcancel": {"type": "object"},
|
|
||||||
"webhookexitfill": {"type": "object"},
|
|
||||||
"webhookstatus": {"type": "object"},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"api_server": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"enabled": {"type": "boolean"},
|
|
||||||
"listen_ip_address": {"format": "ipv4"},
|
|
||||||
"listen_port": {"type": "integer", "minimum": 1024, "maximum": 65535},
|
|
||||||
"username": {"type": "string"},
|
|
||||||
"password": {"type": "string"},
|
|
||||||
"jwt_secret_key": {"type": "string"},
|
|
||||||
"CORS_origins": {"type": "array", "items": {"type": "string"}},
|
|
||||||
"verbosity": {"type": "string", "enum": ["error", "info"]},
|
|
||||||
},
|
|
||||||
"required": ["enabled", "listen_ip_address", "listen_port", "username", "password"],
|
|
||||||
},
|
|
||||||
"db_url": {"type": "string"},
|
|
||||||
"export": {"type": "string", "enum": EXPORT_OPTIONS, "default": "trades"},
|
|
||||||
"disableparamexport": {"type": "boolean"},
|
|
||||||
"initial_state": {"type": "string", "enum": ["running", "stopped"]},
|
|
||||||
"force_entry_enable": {"type": "boolean"},
|
|
||||||
"disable_dataframe_checks": {"type": "boolean"},
|
|
||||||
"internals": {
|
|
||||||
"type": "object",
|
|
||||||
"default": {},
|
|
||||||
"properties": {
|
|
||||||
"process_throttle_secs": {"type": "integer"},
|
|
||||||
"interval": {"type": "integer"},
|
|
||||||
"sd_notify": {"type": "boolean"},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"dataformat_ohlcv": {"type": "string", "enum": AVAILABLE_DATAHANDLERS, "default": "json"},
|
|
||||||
"dataformat_trades": {
|
|
||||||
"type": "string",
|
|
||||||
"enum": AVAILABLE_DATAHANDLERS,
|
|
||||||
"default": "jsongz",
|
|
||||||
},
|
|
||||||
"position_adjustment_enable": {"type": "boolean"},
|
|
||||||
"max_entry_position_adjustment": {"type": ["integer", "number"], "minimum": -1},
|
|
||||||
},
|
|
||||||
"definitions": {
|
|
||||||
"exchange": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"name": {"type": "string"},
|
|
||||||
"sandbox": {"type": "boolean", "default": False},
|
|
||||||
"key": {"type": "string", "default": ""},
|
|
||||||
"secret": {"type": "string", "default": ""},
|
|
||||||
"password": {"type": "string", "default": ""},
|
|
||||||
"uid": {"type": "string"},
|
|
||||||
"pair_whitelist": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string",
|
|
||||||
},
|
|
||||||
"uniqueItems": True,
|
|
||||||
},
|
|
||||||
"pair_blacklist": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string",
|
|
||||||
},
|
|
||||||
"uniqueItems": True,
|
|
||||||
},
|
|
||||||
"unknown_fee_rate": {"type": "number"},
|
|
||||||
"outdated_offset": {"type": "integer", "minimum": 1},
|
|
||||||
"markets_refresh_interval": {"type": "integer"},
|
|
||||||
"ccxt_config": {"type": "object"},
|
|
||||||
"ccxt_async_config": {"type": "object"},
|
|
||||||
},
|
|
||||||
"required": ["name"],
|
|
||||||
},
|
|
||||||
"edge": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"enabled": {"type": "boolean"},
|
|
||||||
"process_throttle_secs": {"type": "integer", "minimum": 600},
|
|
||||||
"calculate_since_number_of_days": {"type": "integer"},
|
|
||||||
"allowed_risk": {"type": "number"},
|
|
||||||
"stoploss_range_min": {"type": "number"},
|
|
||||||
"stoploss_range_max": {"type": "number"},
|
|
||||||
"stoploss_range_step": {"type": "number"},
|
|
||||||
"minimum_winrate": {"type": "number"},
|
|
||||||
"minimum_expectancy": {"type": "number"},
|
|
||||||
"min_trade_number": {"type": "number"},
|
|
||||||
"max_trade_duration_minute": {"type": "integer"},
|
|
||||||
"remove_pumps": {"type": "boolean"},
|
|
||||||
},
|
|
||||||
"required": ["process_throttle_secs", "allowed_risk"],
|
|
||||||
},
|
},
|
||||||
"freqai": {
|
"freqai": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
@ -516,43 +474,43 @@ CONF_SCHEMA = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
SCHEMA_TRADE_REQUIRED = [
|
SCHEMA_TRADE_REQUIRED = [
|
||||||
"exchange",
|
'exchange',
|
||||||
"timeframe",
|
'timeframe',
|
||||||
"max_open_trades",
|
'max_open_trades',
|
||||||
"stake_currency",
|
'stake_currency',
|
||||||
"stake_amount",
|
'stake_amount',
|
||||||
"tradable_balance_ratio",
|
'tradable_balance_ratio',
|
||||||
"last_stake_amount_min_ratio",
|
'last_stake_amount_min_ratio',
|
||||||
"dry_run",
|
'dry_run',
|
||||||
"dry_run_wallet",
|
'dry_run_wallet',
|
||||||
"exit_pricing",
|
'exit_pricing',
|
||||||
"entry_pricing",
|
'entry_pricing',
|
||||||
"stoploss",
|
'stoploss',
|
||||||
"minimal_roi",
|
'minimal_roi',
|
||||||
"internals",
|
'internals',
|
||||||
"dataformat_ohlcv",
|
'dataformat_ohlcv',
|
||||||
"dataformat_trades",
|
'dataformat_trades',
|
||||||
]
|
]
|
||||||
|
|
||||||
SCHEMA_BACKTEST_REQUIRED = [
|
SCHEMA_BACKTEST_REQUIRED = [
|
||||||
"exchange",
|
'exchange',
|
||||||
"max_open_trades",
|
'max_open_trades',
|
||||||
"stake_currency",
|
'stake_currency',
|
||||||
"stake_amount",
|
'stake_amount',
|
||||||
"dry_run_wallet",
|
'dry_run_wallet',
|
||||||
"dataformat_ohlcv",
|
'dataformat_ohlcv',
|
||||||
"dataformat_trades",
|
'dataformat_trades',
|
||||||
]
|
]
|
||||||
SCHEMA_BACKTEST_REQUIRED_FINAL = SCHEMA_BACKTEST_REQUIRED + [
|
SCHEMA_BACKTEST_REQUIRED_FINAL = SCHEMA_BACKTEST_REQUIRED + [
|
||||||
"stoploss",
|
'stoploss',
|
||||||
"minimal_roi",
|
'minimal_roi',
|
||||||
]
|
]
|
||||||
|
|
||||||
SCHEMA_MINIMAL_REQUIRED = [
|
SCHEMA_MINIMAL_REQUIRED = [
|
||||||
"exchange",
|
'exchange',
|
||||||
"dry_run",
|
'dry_run',
|
||||||
"dataformat_ohlcv",
|
'dataformat_ohlcv',
|
||||||
"dataformat_trades",
|
'dataformat_trades',
|
||||||
]
|
]
|
||||||
|
|
||||||
CANCEL_REASON = {
|
CANCEL_REASON = {
|
||||||
|
Loading…
Reference in New Issue
Block a user