Merged with develop

This commit is contained in:
Sam Germain
2021-09-09 13:56:46 -06:00
33 changed files with 254 additions and 225 deletions

View File

@@ -22,7 +22,7 @@ if __version__ == 'develop':
# subprocess.check_output(
# ['git', 'log', '--format="%h"', '-n 1'],
# stderr=subprocess.DEVNULL).decode("utf-8").rstrip().strip('"')
except Exception:
except Exception: # pragma: no cover
# git not available, ignore
try:
# Try Fallback to freqtrade_commit file (created by CI while building docker image)

View File

@@ -61,13 +61,13 @@ def ask_user_config() -> Dict[str, Any]:
"type": "text",
"name": "stake_currency",
"message": "Please insert your stake currency:",
"default": 'BTC',
"default": 'USDT',
},
{
"type": "text",
"name": "stake_amount",
"message": f"Please insert your stake amount (Number or '{UNLIMITED_STAKE_AMOUNT}'):",
"default": "0.01",
"default": "100",
"validate": lambda val: val == UNLIMITED_STAKE_AMOUNT or validate_is_float(val),
"filter": lambda val: '"' + UNLIMITED_STAKE_AMOUNT + '"'
if val == UNLIMITED_STAKE_AMOUNT
@@ -105,6 +105,8 @@ def ask_user_config() -> Dict[str, Any]:
"bittrex",
"kraken",
"ftx",
"kucoin",
"gateio",
Separator(),
"other",
],
@@ -128,6 +130,12 @@ def ask_user_config() -> Dict[str, Any]:
"message": "Insert Exchange Secret",
"when": lambda x: not x['dry_run']
},
{
"type": "password",
"name": "exchange_key_password",
"message": "Insert Exchange API Key password",
"when": lambda x: not x['dry_run'] and x['exchange_name'] == 'kucoin'
},
{
"type": "confirm",
"name": "telegram",

View File

@@ -18,6 +18,7 @@ class Binance(Exchange):
_ft_has: Dict = {
"stoploss_on_exchange": True,
"order_time_in_force": ['gtc', 'fok', 'ioc'],
"time_in_force_parameter": "timeInForce",
"ohlcv_candle_limit": 1000,
"trades_pagination": "id",
"trades_pagination_arg": "fromId",

View File

@@ -54,12 +54,16 @@ class Exchange:
# Parameters to add directly to buy/sell calls (like agreeing to trading agreement)
_params: Dict = {}
# Additional headers - added to the ccxt object
_headers: Dict = {}
# Dict to specify which options each exchange implements
# This defines defaults, which can be selectively overridden by subclasses using _ft_has
# or by specifying them in the configuration.
_ft_has_default: Dict = {
"stoploss_on_exchange": False,
"order_time_in_force": ["gtc"],
"time_in_force_parameter": "timeInForce",
"ohlcv_params": {},
"ohlcv_candle_limit": 500,
"ohlcv_partial_candle": True,
@@ -169,7 +173,7 @@ class Exchange:
asyncio.get_event_loop().run_until_complete(self._api_async.close())
def _init_ccxt(self, exchange_config: Dict[str, Any], ccxt_module: CcxtModuleType = ccxt,
ccxt_kwargs: dict = None) -> ccxt.Exchange:
ccxt_kwargs: Dict = {}) -> ccxt.Exchange:
"""
Initialize ccxt with given config and return valid
ccxt instance.
@@ -188,6 +192,10 @@ class Exchange:
}
if ccxt_kwargs:
logger.info('Applying additional ccxt config: %s', ccxt_kwargs)
if self._headers:
# Inject static headers after the above output to not confuse users.
ccxt_kwargs = deep_merge_dicts({'headers': self._headers}, ccxt_kwargs)
if ccxt_kwargs:
ex_config.update(ccxt_kwargs)
try:
@@ -716,7 +724,8 @@ class Exchange:
params = self._params.copy()
if time_in_force != 'gtc' and ordertype != 'market':
params.update({'timeInForce': time_in_force})
param = self._ft_has.get('time_in_force_parameter', '')
params.update({param: time_in_force})
try:
# Set the precision for amount and price(rate) as accepted by the exchange

View File

@@ -21,4 +21,6 @@ class Kucoin(Exchange):
_ft_has: Dict = {
"l2_limit_range": [20, 100],
"l2_limit_range_required": False,
"order_time_in_force": ['gtc', 'fok', 'ioc'],
"time_in_force_parameter": "timeInForce",
}

View File

@@ -99,7 +99,7 @@ class FreqtradeBot(LoggingMixin):
self.state = State[initial_state.upper()] if initial_state else State.STOPPED
# Protect sell-logic from forcesell and vice versa
self._sell_lock = Lock()
self._exit_lock = Lock()
LoggingMixin.__init__(self, logger, timeframe_to_seconds(self.strategy.timeframe))
def notify_status(self, msg: str) -> None:
@@ -166,14 +166,14 @@ class FreqtradeBot(LoggingMixin):
self.strategy.analyze(self.active_pair_whitelist)
with self._sell_lock:
with self._exit_lock:
# Check and handle any timed out open orders
self.check_handle_timedout()
# Protect from collisions with forcesell.
# Without this, freqtrade my try to recreate stoploss_on_exchange orders
# while selling is in process, since telegram messages arrive in an different thread.
with self._sell_lock:
with self._exit_lock:
trades = Trade.get_open_trades()
# First process current opened trades (positions)
self.exit_positions(trades)
@@ -296,9 +296,9 @@ class FreqtradeBot(LoggingMixin):
if sell_order:
self.refind_lost_order(trade)
else:
self.reupdate_buy_order_fees(trade)
self.reupdate_enter_order_fees(trade)
def reupdate_buy_order_fees(self, trade: Trade):
def reupdate_enter_order_fees(self, trade: Trade):
"""
Get buy order from database, and try to reupdate.
Handles trades where the initial fee-update did not work.
@@ -476,21 +476,21 @@ class FreqtradeBot(LoggingMixin):
time_in_force = self.strategy.order_time_in_force['buy']
if price:
buy_limit_requested = price
enter_limit_requested = price
else:
# Calculate price
proposed_buy_rate = self.exchange.get_rate(pair, refresh=True, side="buy")
proposed_enter_rate = self.exchange.get_rate(pair, refresh=True, side="buy")
custom_entry_price = strategy_safe_wrapper(self.strategy.custom_entry_price,
default_retval=proposed_buy_rate)(
default_retval=proposed_enter_rate)(
pair=pair, current_time=datetime.now(timezone.utc),
proposed_rate=proposed_buy_rate)
proposed_rate=proposed_enter_rate)
buy_limit_requested = self.get_valid_price(custom_entry_price, proposed_buy_rate)
enter_limit_requested = self.get_valid_price(custom_entry_price, proposed_enter_rate)
if not buy_limit_requested:
if not enter_limit_requested:
raise PricingError('Could not determine buy price.')
min_stake_amount = self.exchange.get_min_pair_stake_amount(pair, buy_limit_requested,
min_stake_amount = self.exchange.get_min_pair_stake_amount(pair, enter_limit_requested,
self.strategy.stoploss)
if not self.edge:
@@ -498,7 +498,7 @@ class FreqtradeBot(LoggingMixin):
stake_amount = strategy_safe_wrapper(self.strategy.custom_stake_amount,
default_retval=stake_amount)(
pair=pair, current_time=datetime.now(timezone.utc),
current_rate=buy_limit_requested, proposed_stake=stake_amount,
current_rate=enter_limit_requested, proposed_stake=stake_amount,
min_stake=min_stake_amount, max_stake=max_stake_amount)
stake_amount = self.wallets._validate_stake_amount(pair, stake_amount, min_stake_amount)
@@ -508,27 +508,27 @@ class FreqtradeBot(LoggingMixin):
logger.info(f"Buy signal found: about create a new trade for {pair} with stake_amount: "
f"{stake_amount} ...")
amount = stake_amount / buy_limit_requested
amount = stake_amount / enter_limit_requested
order_type = self.strategy.order_types['buy']
if forcebuy:
# Forcebuy can define a different ordertype
order_type = self.strategy.order_types.get('forcebuy', order_type)
if not strategy_safe_wrapper(self.strategy.confirm_trade_entry, default_retval=True)(
pair=pair, order_type=order_type, amount=amount, rate=buy_limit_requested,
pair=pair, order_type=order_type, amount=amount, rate=enter_limit_requested,
time_in_force=time_in_force, current_time=datetime.now(timezone.utc)):
logger.info(f"User requested abortion of buying {pair}")
return False
amount = self.exchange.amount_to_precision(pair, amount)
order = self.exchange.create_order(pair=pair, ordertype=order_type, side="buy",
amount=amount, rate=buy_limit_requested,
amount=amount, rate=enter_limit_requested,
time_in_force=time_in_force)
order_obj = Order.parse_from_ccxt_object(order, pair, 'buy')
order_id = order['id']
order_status = order.get('status', None)
# we assume the order is executed at the price requested
buy_limit_filled_price = buy_limit_requested
enter_limit_filled_price = enter_limit_requested
amount_requested = amount
if order_status == 'expired' or order_status == 'rejected':
@@ -551,13 +551,13 @@ class FreqtradeBot(LoggingMixin):
)
stake_amount = order['cost']
amount = safe_value_fallback(order, 'filled', 'amount')
buy_limit_filled_price = safe_value_fallback(order, 'average', 'price')
enter_limit_filled_price = safe_value_fallback(order, 'average', 'price')
# in case of FOK the order may be filled immediately and fully
elif order_status == 'closed':
stake_amount = order['cost']
amount = safe_value_fallback(order, 'filled', 'amount')
buy_limit_filled_price = safe_value_fallback(order, 'average', 'price')
enter_limit_filled_price = safe_value_fallback(order, 'average', 'price')
# Fee is applied twice because we make a LIMIT_BUY and LIMIT_SELL
fee = self.exchange.get_fee(symbol=pair, taker_or_maker='maker')
@@ -569,8 +569,8 @@ class FreqtradeBot(LoggingMixin):
amount_requested=amount_requested,
fee_open=fee,
fee_close=fee,
open_rate=buy_limit_filled_price,
open_rate_requested=buy_limit_requested,
open_rate=enter_limit_filled_price,
open_rate_requested=enter_limit_requested,
open_date=datetime.utcnow(),
exchange=self.exchange.id,
open_order_id=order_id,
@@ -590,11 +590,11 @@ class FreqtradeBot(LoggingMixin):
# Updating wallets
self.wallets.update()
self._notify_buy(trade, order_type)
self._notify_enter(trade, order_type)
return True
def _notify_buy(self, trade: Trade, order_type: str) -> None:
def _notify_enter(self, trade: Trade, order_type: str) -> None:
"""
Sends rpc notification when a buy occurred.
"""
@@ -617,7 +617,7 @@ class FreqtradeBot(LoggingMixin):
# Send the message
self.rpc.send_msg(msg)
def _notify_buy_cancel(self, trade: Trade, order_type: str, reason: str) -> None:
def _notify_enter_cancel(self, trade: Trade, order_type: str, reason: str) -> None:
"""
Sends rpc notification when a buy cancel occurred.
"""
@@ -643,7 +643,7 @@ class FreqtradeBot(LoggingMixin):
# Send the message
self.rpc.send_msg(msg)
def _notify_buy_fill(self, trade: Trade) -> None:
def _notify_enter_fill(self, trade: Trade) -> None:
msg = {
'trade_id': trade.id,
'type': RPCMessageType.BUY_FILL,
@@ -713,8 +713,8 @@ class FreqtradeBot(LoggingMixin):
)
logger.debug('checking sell')
sell_rate = self.exchange.get_rate(trade.pair, refresh=True, side="sell")
if self._check_and_execute_sell(trade, sell_rate, buy, sell):
exit_rate = self.exchange.get_rate(trade.pair, refresh=True, side="sell")
if self._check_and_execute_exit(trade, exit_rate, buy, sell):
return True
logger.debug('Found no sell signal for %s.', trade)
@@ -744,7 +744,7 @@ class FreqtradeBot(LoggingMixin):
except InvalidOrderException as e:
trade.stoploss_order_id = None
logger.error(f'Unable to place a stoploss order on exchange. {e}')
logger.warning('Selling the trade forcefully')
logger.warning('Exiting the trade forcefully')
self.execute_trade_exit(trade, trade.stop_loss, sell_reason=SellCheckTuple(
sell_type=SellType.EMERGENCY_SELL))
@@ -782,7 +782,7 @@ class FreqtradeBot(LoggingMixin):
# Lock pair for one candle to prevent immediate rebuys
self.strategy.lock_pair(trade.pair, datetime.now(timezone.utc),
reason='Auto lock')
self._notify_sell(trade, "stoploss")
self._notify_exit(trade, "stoploss")
return True
if trade.open_order_id or not trade.is_open:
@@ -851,19 +851,19 @@ class FreqtradeBot(LoggingMixin):
logger.warning(f"Could not create trailing stoploss order "
f"for pair {trade.pair}.")
def _check_and_execute_sell(self, trade: Trade, sell_rate: float,
def _check_and_execute_exit(self, trade: Trade, exit_rate: float,
buy: bool, sell: bool) -> bool:
"""
Check and execute sell
Check and execute exit
"""
should_sell = self.strategy.should_sell(
trade, sell_rate, datetime.now(timezone.utc), buy, sell,
trade, exit_rate, datetime.now(timezone.utc), buy, sell,
force_stoploss=self.edge.stoploss(trade.pair) if self.edge else 0
)
if should_sell.sell_flag:
logger.info(f'Executing Sell for {trade.pair}. Reason: {should_sell.sell_type}')
self.execute_trade_exit(trade, sell_rate, should_sell)
self.execute_trade_exit(trade, exit_rate, should_sell)
return True
return False
@@ -906,7 +906,7 @@ class FreqtradeBot(LoggingMixin):
default_retval=False)(pair=trade.pair,
trade=trade,
order=order))):
self.handle_cancel_buy(trade, order, constants.CANCEL_REASON['TIMEOUT'])
self.handle_cancel_enter(trade, order, constants.CANCEL_REASON['TIMEOUT'])
elif (order['side'] == 'sell' and (order['status'] == 'open' or fully_cancelled) and (
fully_cancelled
@@ -915,7 +915,7 @@ class FreqtradeBot(LoggingMixin):
default_retval=False)(pair=trade.pair,
trade=trade,
order=order))):
self.handle_cancel_sell(trade, order, constants.CANCEL_REASON['TIMEOUT'])
self.handle_cancel_exit(trade, order, constants.CANCEL_REASON['TIMEOUT'])
def cancel_all_open_orders(self) -> None:
"""
@@ -931,13 +931,13 @@ class FreqtradeBot(LoggingMixin):
continue
if order['side'] == 'buy':
self.handle_cancel_buy(trade, order, constants.CANCEL_REASON['ALL_CANCELLED'])
self.handle_cancel_enter(trade, order, constants.CANCEL_REASON['ALL_CANCELLED'])
elif order['side'] == 'sell':
self.handle_cancel_sell(trade, order, constants.CANCEL_REASON['ALL_CANCELLED'])
self.handle_cancel_exit(trade, order, constants.CANCEL_REASON['ALL_CANCELLED'])
Trade.commit()
def handle_cancel_buy(self, trade: Trade, order: Dict, reason: str) -> bool:
def handle_cancel_enter(self, trade: Trade, order: Dict, reason: str) -> bool:
"""
Buy cancel - cancel order
:return: True if order was fully cancelled
@@ -994,11 +994,11 @@ class FreqtradeBot(LoggingMixin):
reason += f", {constants.CANCEL_REASON['PARTIALLY_FILLED']}"
self.wallets.update()
self._notify_buy_cancel(trade, order_type=self.strategy.order_types['buy'],
reason=reason)
self._notify_enter_cancel(trade, order_type=self.strategy.order_types['buy'],
reason=reason)
return was_trade_fully_canceled
def handle_cancel_sell(self, trade: Trade, order: Dict, reason: str) -> str:
def handle_cancel_exit(self, trade: Trade, order: Dict, reason: str) -> str:
"""
Sell cancel - cancel order and update trade
:return: Reason for cancel
@@ -1032,14 +1032,14 @@ class FreqtradeBot(LoggingMixin):
reason = constants.CANCEL_REASON['PARTIALLY_FILLED_KEEP_OPEN']
self.wallets.update()
self._notify_sell_cancel(
self._notify_exit_cancel(
trade,
order_type=self.strategy.order_types['sell'],
reason=reason
)
return reason
def _safe_sell_amount(self, pair: str, amount: float) -> float:
def _safe_exit_amount(self, pair: str, amount: float) -> float:
"""
Get sellable amount.
Should be trade.amount - but will fall back to the available amount if necessary.
@@ -1111,7 +1111,7 @@ class FreqtradeBot(LoggingMixin):
# but we allow this value to be changed)
order_type = self.strategy.order_types.get("forcesell", order_type)
amount = self._safe_sell_amount(trade.pair, trade.amount)
amount = self._safe_exit_amount(trade.pair, trade.amount)
time_in_force = self.strategy.order_time_in_force['sell']
if not strategy_safe_wrapper(self.strategy.confirm_trade_exit, default_retval=True)(
@@ -1150,11 +1150,11 @@ class FreqtradeBot(LoggingMixin):
self.strategy.lock_pair(trade.pair, datetime.now(timezone.utc),
reason='Auto lock')
self._notify_sell(trade, order_type)
self._notify_exit(trade, order_type)
return True
def _notify_sell(self, trade: Trade, order_type: str, fill: bool = False) -> None:
def _notify_exit(self, trade: Trade, order_type: str, fill: bool = False) -> None:
"""
Sends rpc notification when a sell occurred.
"""
@@ -1196,7 +1196,7 @@ class FreqtradeBot(LoggingMixin):
# Send the message
self.rpc.send_msg(msg)
def _notify_sell_cancel(self, trade: Trade, order_type: str, reason: str) -> None:
def _notify_exit_cancel(self, trade: Trade, order_type: str, reason: str) -> None:
"""
Sends rpc notification when a sell cancel occurred.
"""
@@ -1291,13 +1291,13 @@ class FreqtradeBot(LoggingMixin):
# Updating wallets when order is closed
if not trade.is_open:
if not stoploss_order and not trade.open_order_id:
self._notify_sell(trade, '', True)
self._notify_exit(trade, '', True)
self.protections.stop_per_pair(trade.pair)
self.protections.global_stop()
self.wallets.update()
elif not trade.open_order_id:
# Buy fill
self._notify_buy_fill(trade)
self._notify_enter_fill(trade)
return False

View File

@@ -87,7 +87,7 @@ def setup_logging(config: Dict[str, Any]) -> None:
# syslog config. The messages should be equal for this.
handler_sl.setFormatter(Formatter('%(name)s - %(levelname)s - %(message)s'))
logging.root.addHandler(handler_sl)
elif s[0] == 'journald':
elif s[0] == 'journald': # pragma: no cover
try:
from systemd.journal import JournaldLogHandler
except ImportError:

View File

@@ -9,7 +9,7 @@ from typing import Any, List
# check min. python version
if sys.version_info < (3, 7):
if sys.version_info < (3, 7): # pragma: no cover
sys.exit("Freqtrade requires Python version >= 3.7")
from freqtrade.commands import Arguments
@@ -46,7 +46,7 @@ def main(sysargv: List[str] = None) -> None:
"`freqtrade --help` or `freqtrade <command> --help`."
)
except SystemExit as e:
except SystemExit as e: # pragma: no cover
return_code = e
except KeyboardInterrupt:
logger.info('SIGINT received, aborting ...')
@@ -60,5 +60,5 @@ def main(sysargv: List[str] = None) -> None:
sys.exit(return_code)
if __name__ == '__main__':
if __name__ == '__main__': # pragma: no cover
main()

View File

@@ -17,7 +17,7 @@ def expand_pairlist(wildcardpl: List[str], available_pairs: List[str],
if keep_invalid:
for pair_wc in wildcardpl:
try:
comp = re.compile(pair_wc)
comp = re.compile(pair_wc, re.IGNORECASE)
result_partial = [
pair for pair in available_pairs if re.fullmatch(comp, pair)
]
@@ -33,7 +33,7 @@ def expand_pairlist(wildcardpl: List[str], available_pairs: List[str],
else:
for pair_wc in wildcardpl:
try:
comp = re.compile(pair_wc)
comp = re.compile(pair_wc, re.IGNORECASE)
result += [
pair for pair in available_pairs if re.fullmatch(comp, pair)
]

View File

@@ -5,6 +5,20 @@ import time
import uvicorn
def asyncio_setup() -> None: # pragma: no cover
# Set eventloop for win32 setups
# Reverts a change done in uvicorn 0.15.0 - which now sets the eventloop
# via policy.
import sys
if sys.version_info >= (3, 8) and sys.platform == "win32":
import asyncio
import selectors
selector = selectors.SelectSelector()
loop = asyncio.SelectorEventLoop(selector)
asyncio.set_event_loop(loop)
class UvicornServer(uvicorn.Server):
"""
Multithreaded server - as found in https://github.com/encode/uvicorn/issues/742
@@ -28,7 +42,7 @@ class UvicornServer(uvicorn.Server):
try:
import uvloop # noqa
except ImportError: # pragma: no cover
from uvicorn.loops.asyncio import asyncio_setup
asyncio_setup()
else:
asyncio.set_event_loop(uvloop.new_event_loop())

View File

@@ -403,8 +403,11 @@ class RPC:
# Doing the sum is not right - overall profit needs to be based on initial capital
profit_all_ratio_sum = sum(profit_all_ratio) if profit_all_ratio else 0.0
starting_balance = self._freqtrade.wallets.get_starting_balance()
profit_closed_ratio_fromstart = profit_closed_coin_sum / starting_balance
profit_all_ratio_fromstart = profit_all_coin_sum / starting_balance
profit_closed_ratio_fromstart = 0
profit_all_ratio_fromstart = 0
if starting_balance:
profit_closed_ratio_fromstart = profit_closed_coin_sum / starting_balance
profit_all_ratio_fromstart = profit_all_coin_sum / starting_balance
profit_all_fiat = self._fiat_converter.convert_amount(
profit_all_coin_sum,
@@ -545,12 +548,12 @@ class RPC:
order = self._freqtrade.exchange.fetch_order(trade.open_order_id, trade.pair)
if order['side'] == 'buy':
fully_canceled = self._freqtrade.handle_cancel_buy(
fully_canceled = self._freqtrade.handle_cancel_enter(
trade, order, CANCEL_REASON['FORCE_SELL'])
if order['side'] == 'sell':
# Cancel order - so it is placed anew with a fresh price.
self._freqtrade.handle_cancel_sell(trade, order, CANCEL_REASON['FORCE_SELL'])
self._freqtrade.handle_cancel_exit(trade, order, CANCEL_REASON['FORCE_SELL'])
if not fully_canceled:
# Get current rate and execute sell
@@ -563,7 +566,7 @@ class RPC:
if self._freqtrade.state != State.RUNNING:
raise RPCException('trader is not running')
with self._freqtrade._sell_lock:
with self._freqtrade._exit_lock:
if trade_id == 'all':
# Execute sell for all open orders
for trade in Trade.get_open_trades():
@@ -625,7 +628,7 @@ class RPC:
Handler for delete <id>.
Delete the given trade and close eventually existing open orders.
"""
with self._freqtrade._sell_lock:
with self._freqtrade._exit_lock:
c_count = 0
trade = Trade.get_trades(trade_filter=[Trade.id == trade_id]).first()
if not trade:

View File

@@ -1,3 +1,10 @@
{%set volume_pairlist = '{
"method": "VolumePairList",
"number_assets": 20,
"sort_key": "quoteVolume",
"min_value": 0,
"refresh_period": 1800
}' %}
{
"max_open_trades": {{ max_open_trades }},
"stake_currency": "{{ stake_currency }}",
@@ -29,7 +36,7 @@
},
{{ exchange | indent(4) }},
"pairlists": [
{"method": "StaticPairList"}
{{ '{"method": "StaticPairList"}' if exchange_name == 'bittrex' else volume_pairlist }}
],
"edge": {
"enabled": false,

View File

@@ -8,34 +8,8 @@
"rateLimit": 200
},
"pair_whitelist": [
"ALGO/BTC",
"ATOM/BTC",
"BAT/BTC",
"BCH/BTC",
"BRD/BTC",
"EOS/BTC",
"ETH/BTC",
"IOTA/BTC",
"LINK/BTC",
"LTC/BTC",
"NEO/BTC",
"NXS/BTC",
"XMR/BTC",
"XRP/BTC",
"XTZ/BTC"
],
"pair_blacklist": [
"BNB/BTC",
"BNB/BUSD",
"BNB/ETH",
"BNB/EUR",
"BNB/NGN",
"BNB/PAX",
"BNB/RUB",
"BNB/TRY",
"BNB/TUSD",
"BNB/USDC",
"BNB/USDS",
"BNB/USDT"
"BNB/.*"
]
}

View File

@@ -15,16 +15,6 @@
"rateLimit": 500
},
"pair_whitelist": [
"ETH/BTC",
"LTC/BTC",
"ETC/BTC",
"DASH/BTC",
"ZEC/BTC",
"XLM/BTC",
"XRP/BTC",
"TRX/BTC",
"ADA/BTC",
"XMR/BTC"
],
"pair_blacklist": [
]

View File

@@ -7,28 +7,10 @@
"ccxt_async_config": {
"enableRateLimit": true,
"rateLimit": 1000
// Enable the below for downoading data.
//"rateLimit": 3100
},
"pair_whitelist": [
"ADA/EUR",
"ATOM/EUR",
"BAT/EUR",
"BCH/EUR",
"BTC/EUR",
"DAI/EUR",
"DASH/EUR",
"EOS/EUR",
"ETC/EUR",
"ETH/EUR",
"LINK/EUR",
"LTC/EUR",
"QTUM/EUR",
"REP/EUR",
"WAVES/EUR",
"XLM/EUR",
"XMR/EUR",
"XRP/EUR",
"XTZ/EUR",
"ZEC/EUR"
],
"pair_blacklist": [

View File

@@ -0,0 +1,18 @@
"exchange": {
"name": "{{ exchange_name | lower }}",
"key": "{{ exchange_key }}",
"secret": "{{ exchange_secret }}",
"password": "{{ exchange_key_password }}",
"ccxt_config": {
"enableRateLimit": true
"rateLimit": 200
},
"ccxt_async_config": {
"enableRateLimit": true,
"rateLimit": 200
},
"pair_whitelist": [
],
"pair_blacklist": [
]
}