commit
4a91ecd91a
@ -1,3 +1,10 @@
|
|||||||
|
[MASTER]
|
||||||
|
extension-pkg-whitelist=numpy,talib
|
||||||
|
|
||||||
[BASIC]
|
[BASIC]
|
||||||
good-names=logger
|
good-names=logger
|
||||||
ignore=vendor
|
ignore=vendor
|
||||||
|
|
||||||
|
[TYPECHECK]
|
||||||
|
ignored-modules=numpy,talib
|
||||||
|
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
""" FreqTrade bot """
|
||||||
__version__ = '0.14.2'
|
__version__ = '0.14.2'
|
||||||
|
|
||||||
from . import main
|
from . import main
|
||||||
|
@ -1,3 +1,6 @@
|
|||||||
|
"""
|
||||||
|
Functions to analyze ticker data with indicators and produce buy and sell signals
|
||||||
|
"""
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
import logging
|
import logging
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
@ -7,11 +10,12 @@ import talib.abstract as ta
|
|||||||
from pandas import DataFrame, to_datetime
|
from pandas import DataFrame, to_datetime
|
||||||
|
|
||||||
from freqtrade.exchange import get_ticker_history
|
from freqtrade.exchange import get_ticker_history
|
||||||
from freqtrade.vendor.qtpylib.indicators import awesome_oscillator, crossed_above, crossed_below
|
from freqtrade.vendor.qtpylib.indicators import awesome_oscillator, crossed_above
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
class SignalType(Enum):
|
class SignalType(Enum):
|
||||||
|
""" Enum to distinguish between buy and sell signals """
|
||||||
BUY = "buy"
|
BUY = "buy"
|
||||||
SELL = "sell"
|
SELL = "sell"
|
||||||
|
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
# pragma pylint: disable=W0603
|
||||||
|
""" Cryptocurrency Exchanges support """
|
||||||
import enum
|
import enum
|
||||||
import logging
|
import logging
|
||||||
from random import randint
|
from random import randint
|
||||||
@ -77,7 +79,7 @@ def validate_pairs(pairs: List[str]) -> None:
|
|||||||
def buy(pair: str, rate: float, amount: float) -> str:
|
def buy(pair: str, rate: float, amount: float) -> str:
|
||||||
if _CONF['dry_run']:
|
if _CONF['dry_run']:
|
||||||
global _DRY_RUN_OPEN_ORDERS
|
global _DRY_RUN_OPEN_ORDERS
|
||||||
order_id = 'dry_run_buy_{}'.format(randint(0, 1e6))
|
order_id = 'dry_run_buy_{}'.format(randint(0, 10**6))
|
||||||
_DRY_RUN_OPEN_ORDERS[order_id] = {
|
_DRY_RUN_OPEN_ORDERS[order_id] = {
|
||||||
'pair': pair,
|
'pair': pair,
|
||||||
'rate': rate,
|
'rate': rate,
|
||||||
@ -95,7 +97,7 @@ def buy(pair: str, rate: float, amount: float) -> str:
|
|||||||
def sell(pair: str, rate: float, amount: float) -> str:
|
def sell(pair: str, rate: float, amount: float) -> str:
|
||||||
if _CONF['dry_run']:
|
if _CONF['dry_run']:
|
||||||
global _DRY_RUN_OPEN_ORDERS
|
global _DRY_RUN_OPEN_ORDERS
|
||||||
order_id = 'dry_run_sell_{}'.format(randint(0, 1e6))
|
order_id = 'dry_run_sell_{}'.format(randint(0, 10**6))
|
||||||
_DRY_RUN_OPEN_ORDERS[order_id] = {
|
_DRY_RUN_OPEN_ORDERS[order_id] = {
|
||||||
'pair': pair,
|
'pair': pair,
|
||||||
'rate': rate,
|
'rate': rate,
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
# pragma pylint: disable=missing-docstring
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
|
|
||||||
@ -11,9 +12,9 @@ def load_backtesting_data(ticker_interval: int = 5):
|
|||||||
]
|
]
|
||||||
for pair in pairs:
|
for pair in pairs:
|
||||||
with open('{abspath}/testdata/{pair}-{ticker_interval}.json'.format(
|
with open('{abspath}/testdata/{pair}-{ticker_interval}.json'.format(
|
||||||
abspath=path,
|
abspath=path,
|
||||||
pair=pair,
|
pair=pair,
|
||||||
ticker_interval=ticker_interval,
|
ticker_interval=ticker_interval,
|
||||||
)) as fp:
|
)) as tickerdata:
|
||||||
result[pair] = json.load(fp)
|
result[pair] = json.load(tickerdata)
|
||||||
return result
|
return result
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
# pragma pylint: disable=missing-docstring
|
# pragma pylint: disable=missing-docstring,W0621
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
import json
|
import json
|
||||||
import pytest
|
import pytest
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
# pragma pylint: disable=missing-docstring
|
# pragma pylint: disable=missing-docstring,W0212
|
||||||
|
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
@ -23,13 +23,13 @@ logger = logging.getLogger(__name__)
|
|||||||
|
|
||||||
|
|
||||||
def format_results(results: DataFrame):
|
def format_results(results: DataFrame):
|
||||||
return 'Made {} buys. Average profit {:.2f}%. ' \
|
return ('Made {} buys. Average profit {:.2f}%. '
|
||||||
'Total profit was {:.3f}. Average duration {:.1f} mins.'.format(
|
'Total profit was {:.3f}. Average duration {:.1f} mins.').format(
|
||||||
len(results.index),
|
len(results.index),
|
||||||
results.profit.mean() * 100.0,
|
results.profit.mean() * 100.0,
|
||||||
results.profit.sum(),
|
results.profit.sum(),
|
||||||
results.duration.mean() * 5,
|
results.duration.mean() * 5,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def preprocess(backdata) -> Dict[str, DataFrame]:
|
def preprocess(backdata) -> Dict[str, DataFrame]:
|
||||||
@ -47,11 +47,11 @@ def get_timeframe(data: Dict[str, Dict]) -> Tuple[arrow.Arrow, arrow.Arrow]:
|
|||||||
"""
|
"""
|
||||||
min_date, max_date = None, None
|
min_date, max_date = None, None
|
||||||
for values in data.values():
|
for values in data.values():
|
||||||
values = sorted(values, key=lambda d: arrow.get(d['T']))
|
sorted_values = sorted(values, key=lambda d: arrow.get(d['T']))
|
||||||
if not min_date or values[0]['T'] < min_date:
|
if not min_date or sorted_values[0]['T'] < min_date:
|
||||||
min_date = values[0]['T']
|
min_date = sorted_values[0]['T']
|
||||||
if not max_date or values[-1]['T'] > max_date:
|
if not max_date or sorted_values[-1]['T'] > max_date:
|
||||||
max_date = values[-1]['T']
|
max_date = sorted_values[-1]['T']
|
||||||
return arrow.get(min_date), arrow.get(max_date)
|
return arrow.get(min_date), arrow.get(max_date)
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
# pragma pylint: disable=missing-docstring
|
# pragma pylint: disable=missing-docstring,C0103
|
||||||
from unittest.mock import MagicMock
|
from unittest.mock import MagicMock
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
@ -33,4 +33,3 @@ def test_validate_pairs_not_compatible(default_conf, mocker):
|
|||||||
mocker.patch.dict('freqtrade.exchange._CONF', default_conf)
|
mocker.patch.dict('freqtrade.exchange._CONF', default_conf)
|
||||||
with pytest.raises(RuntimeError, match=r'not compatible'):
|
with pytest.raises(RuntimeError, match=r'not compatible'):
|
||||||
validate_pairs(default_conf['exchange']['pair_whitelist'])
|
validate_pairs(default_conf['exchange']['pair_whitelist'])
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
# pragma pylint: disable=missing-docstring
|
# pragma pylint: disable=missing-docstring,W0212
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
from functools import reduce
|
from functools import reduce
|
||||||
@ -21,6 +21,7 @@ logging.disable(logging.DEBUG) # disable debug logs that slow backtesting a lot
|
|||||||
# set TARGET_TRADES to suit your number concurrent trades so its realistic to 20days of data
|
# set TARGET_TRADES to suit your number concurrent trades so its realistic to 20days of data
|
||||||
TARGET_TRADES = 1100
|
TARGET_TRADES = 1100
|
||||||
TOTAL_TRIES = 4
|
TOTAL_TRIES = 4
|
||||||
|
# pylint: disable=C0103
|
||||||
current_tries = 0
|
current_tries = 0
|
||||||
|
|
||||||
|
|
||||||
@ -90,6 +91,7 @@ def test_hyperopt(backtest_conf, mocker):
|
|||||||
trade_loss = 1 - 0.35 * exp(-(trade_count - TARGET_TRADES) ** 2 / 10 ** 5.2)
|
trade_loss = 1 - 0.35 * exp(-(trade_count - TARGET_TRADES) ** 2 / 10 ** 5.2)
|
||||||
profit_loss = max(0, 1 - total_profit / 10000) # max profit 10000
|
profit_loss = max(0, 1 - total_profit / 10000) # max profit 10000
|
||||||
|
|
||||||
|
# pylint: disable=W0603
|
||||||
global current_tries
|
global current_tries
|
||||||
current_tries += 1
|
current_tries += 1
|
||||||
print('{}/{}: {}'.format(current_tries, TOTAL_TRIES, result))
|
print('{}/{}: {}'.format(current_tries, TOTAL_TRIES, result))
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
# pragma pylint: disable=missing-docstring
|
# pragma pylint: disable=missing-docstring,C0103
|
||||||
import copy
|
import copy
|
||||||
from unittest.mock import MagicMock
|
from unittest.mock import MagicMock
|
||||||
|
|
||||||
@ -26,7 +26,7 @@ def test_process_trade_creation(default_conf, ticker, health, mocker):
|
|||||||
init(default_conf, create_engine('sqlite://'))
|
init(default_conf, create_engine('sqlite://'))
|
||||||
|
|
||||||
trades = Trade.query.filter(Trade.is_open.is_(True)).all()
|
trades = Trade.query.filter(Trade.is_open.is_(True)).all()
|
||||||
assert len(trades) == 0
|
assert not trades
|
||||||
|
|
||||||
result = _process()
|
result = _process()
|
||||||
assert result is True
|
assert result is True
|
||||||
@ -81,7 +81,8 @@ def test_process_runtime_error(default_conf, ticker, health, mocker):
|
|||||||
def test_process_trade_handling(default_conf, ticker, limit_buy_order, health, mocker):
|
def test_process_trade_handling(default_conf, ticker, limit_buy_order, health, mocker):
|
||||||
mocker.patch.dict('freqtrade.main._CONF', default_conf)
|
mocker.patch.dict('freqtrade.main._CONF', default_conf)
|
||||||
mocker.patch.multiple('freqtrade.main.telegram', init=MagicMock(), send_msg=MagicMock())
|
mocker.patch.multiple('freqtrade.main.telegram', init=MagicMock(), send_msg=MagicMock())
|
||||||
signal = mocker.patch('freqtrade.main.get_signal', side_effect=lambda *args: False if args[1] == SignalType.SELL else True)
|
mocker.patch('freqtrade.main.get_signal',
|
||||||
|
side_effect=lambda *args: False if args[1] == SignalType.SELL else True)
|
||||||
mocker.patch.multiple('freqtrade.main.exchange',
|
mocker.patch.multiple('freqtrade.main.exchange',
|
||||||
validate_pairs=MagicMock(),
|
validate_pairs=MagicMock(),
|
||||||
get_ticker=ticker,
|
get_ticker=ticker,
|
||||||
@ -91,7 +92,7 @@ def test_process_trade_handling(default_conf, ticker, limit_buy_order, health, m
|
|||||||
init(default_conf, create_engine('sqlite://'))
|
init(default_conf, create_engine('sqlite://'))
|
||||||
|
|
||||||
trades = Trade.query.filter(Trade.is_open.is_(True)).all()
|
trades = Trade.query.filter(Trade.is_open.is_(True)).all()
|
||||||
assert len(trades) == 0
|
assert not trades
|
||||||
result = _process()
|
result = _process()
|
||||||
assert result is True
|
assert result is True
|
||||||
trades = Trade.query.filter(Trade.is_open.is_(True)).all()
|
trades = Trade.query.filter(Trade.is_open.is_(True)).all()
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
# pragma pylint: disable=missing-docstring
|
# pragma pylint: disable=missing-docstring,C0103
|
||||||
import time
|
import time
|
||||||
import os
|
import os
|
||||||
from argparse import Namespace
|
from argparse import Namespace
|
||||||
|
@ -1,10 +1,9 @@
|
|||||||
# pragma pylint: disable=missing-docstring, too-many-arguments, too-many-ancestors
|
# pragma pylint: disable=missing-docstring, too-many-arguments, too-many-ancestors, C0103
|
||||||
import re
|
import re
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from random import randint
|
from random import randint
|
||||||
from unittest.mock import MagicMock
|
from unittest.mock import MagicMock
|
||||||
|
|
||||||
import pytest
|
|
||||||
from sqlalchemy import create_engine
|
from sqlalchemy import create_engine
|
||||||
from telegram import Update, Message, Chat
|
from telegram import Update, Message, Chat
|
||||||
from telegram.error import NetworkError
|
from telegram.error import NetworkError
|
||||||
@ -519,7 +518,7 @@ def test_send_msg(default_conf, mocker):
|
|||||||
init=MagicMock())
|
init=MagicMock())
|
||||||
bot = MagicMock()
|
bot = MagicMock()
|
||||||
send_msg('test', bot)
|
send_msg('test', bot)
|
||||||
assert len(bot.method_calls) == 0
|
assert not bot.method_calls
|
||||||
bot.reset_mock()
|
bot.reset_mock()
|
||||||
|
|
||||||
default_conf['telegram']['enabled'] = True
|
default_conf['telegram']['enabled'] = True
|
||||||
|
Loading…
Reference in New Issue
Block a user