commit
781b9b6dd4
@ -6,7 +6,7 @@ import sys
|
||||
import time
|
||||
import traceback
|
||||
from datetime import datetime
|
||||
from typing import Dict, List, Optional
|
||||
from typing import Dict, List, Optional, Any
|
||||
|
||||
import arrow
|
||||
import requests
|
||||
@ -23,7 +23,7 @@ from freqtrade.strategy.strategy import Strategy
|
||||
|
||||
logger = logging.getLogger('freqtrade')
|
||||
|
||||
_CONF = {}
|
||||
_CONF: Dict[str, Any] = {}
|
||||
|
||||
|
||||
def refresh_whitelist(whitelist: List[str]) -> List[str]:
|
||||
@ -55,7 +55,7 @@ def refresh_whitelist(whitelist: List[str]) -> List[str]:
|
||||
return final_list
|
||||
|
||||
|
||||
def process_maybe_execute_buy(conf, interval):
|
||||
def process_maybe_execute_buy(interval):
|
||||
"""
|
||||
Tries to execute a buy trade in a safe way
|
||||
:return: True if executed
|
||||
@ -64,12 +64,12 @@ def process_maybe_execute_buy(conf, interval):
|
||||
# Create entity and execute trade
|
||||
if create_trade(float(_CONF['stake_amount']), interval):
|
||||
return True
|
||||
else:
|
||||
logger.info(
|
||||
'Checked all whitelisted currencies. '
|
||||
'Found no suitable entry positions for buying. Will keep looking ...'
|
||||
)
|
||||
return False
|
||||
|
||||
logger.info(
|
||||
'Checked all whitelisted currencies. '
|
||||
'Found no suitable entry positions for buying. Will keep looking ...'
|
||||
)
|
||||
return False
|
||||
except DependencyException as exception:
|
||||
logger.warning('Unable to create trade: %s', exception)
|
||||
return False
|
||||
@ -115,7 +115,7 @@ def _process(interval: int, nb_assets: Optional[int] = 0) -> bool:
|
||||
# Query trades from persistence layer
|
||||
trades = Trade.query.filter(Trade.is_open.is_(True)).all()
|
||||
if len(trades) < _CONF['max_open_trades']:
|
||||
state_changed = process_maybe_execute_buy(_CONF, interval)
|
||||
state_changed = process_maybe_execute_buy(interval)
|
||||
|
||||
for trade in trades:
|
||||
state_changed |= process_maybe_execute_sell(trade, interval)
|
||||
@ -159,16 +159,16 @@ def handle_timedout_limit_buy(trade: Trade, order: Dict) -> bool:
|
||||
rpc.send_msg('*Timeout:* Unfilled buy order for {} cancelled'.format(
|
||||
trade.pair.replace('_', '/')))
|
||||
return True
|
||||
else:
|
||||
# if trade is partially complete, edit the stake details for the trade
|
||||
# and close the order
|
||||
trade.amount = order['amount'] - order['remaining']
|
||||
trade.stake_amount = trade.amount * trade.open_rate
|
||||
trade.open_order_id = None
|
||||
logger.info('Partial buy order timeout for %s.', trade)
|
||||
rpc.send_msg('*Timeout:* Remaining buy order for {} cancelled'.format(
|
||||
trade.pair.replace('_', '/')))
|
||||
return False
|
||||
|
||||
# if trade is partially complete, edit the stake details for the trade
|
||||
# and close the order
|
||||
trade.amount = order['amount'] - order['remaining']
|
||||
trade.stake_amount = trade.amount * trade.open_rate
|
||||
trade.open_order_id = None
|
||||
logger.info('Partial buy order timeout for %s.', trade)
|
||||
rpc.send_msg('*Timeout:* Remaining buy order for {} cancelled'.format(
|
||||
trade.pair.replace('_', '/')))
|
||||
return False
|
||||
|
||||
|
||||
# FIX: 20180110, should cancel_order() be cond. or unconditionally called?
|
||||
@ -189,9 +189,9 @@ def handle_timedout_limit_sell(trade: Trade, order: Dict) -> bool:
|
||||
trade.pair.replace('_', '/')))
|
||||
logger.info('Sell order timeout for %s.', trade)
|
||||
return True
|
||||
else:
|
||||
# TODO: figure out how to handle partially complete sell orders
|
||||
return False
|
||||
|
||||
# TODO: figure out how to handle partially complete sell orders
|
||||
return False
|
||||
|
||||
|
||||
def check_handle_timedout(timeoutvalue: int) -> None:
|
||||
|
@ -22,8 +22,8 @@ def trim_tickerlist(tickerlist, timerange):
|
||||
return tickerlist[0:start]
|
||||
elif stype == ('index', 'index'):
|
||||
return tickerlist[start:stop]
|
||||
else:
|
||||
return tickerlist
|
||||
|
||||
return tickerlist
|
||||
|
||||
|
||||
def load_tickerdata_file(datadir, pair, ticker_interval,
|
||||
|
@ -26,7 +26,7 @@ def get_timeframe(data: Dict[str, DataFrame]) -> Tuple[arrow.Arrow, arrow.Arrow]
|
||||
:return: tuple containing min_date, max_date
|
||||
"""
|
||||
all_dates = Series([])
|
||||
for pair, pair_data in data.items():
|
||||
for pair_data in data.values():
|
||||
all_dates = all_dates.append(pair_data['date'])
|
||||
all_dates.sort_values(inplace=True)
|
||||
return arrow.get(all_dates.iloc[0]), arrow.get(all_dates.iloc[-1])
|
||||
@ -212,7 +212,10 @@ def start(args):
|
||||
preprocessed = optimize.tickerdata_to_dataframe(data)
|
||||
# Print timeframe
|
||||
min_date, max_date = get_timeframe(preprocessed)
|
||||
logger.info('Measuring data from %s up to %s ...', min_date.isoformat(), max_date.isoformat())
|
||||
logger.info('Measuring data from %s up to %s (%s days)..',
|
||||
min_date.isoformat(),
|
||||
max_date.isoformat(),
|
||||
(max_date-min_date).days)
|
||||
# Execute backtest and print results
|
||||
sell_profit_only = config.get('experimental', {}).get('sell_profit_only', False)
|
||||
use_sell_signal = config.get('experimental', {}).get('use_sell_signal', False)
|
||||
|
@ -10,7 +10,7 @@ import sys
|
||||
from functools import reduce
|
||||
from math import exp
|
||||
from operator import itemgetter
|
||||
from typing import Dict, List
|
||||
from typing import Dict, Any, Callable
|
||||
|
||||
import numpy
|
||||
import talib.abstract as ta
|
||||
@ -35,7 +35,7 @@ logging.getLogger('hyperopt.tpe').setLevel(logging.WARNING)
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# 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 the number of days
|
||||
TARGET_TRADES = 600
|
||||
TOTAL_TRIES = 0
|
||||
_CURRENT_TRIES = 0
|
||||
@ -225,7 +225,7 @@ def calculate_loss(total_profit: float, trade_count: int, trade_duration: float)
|
||||
return trade_loss + profit_loss + duration_loss
|
||||
|
||||
|
||||
def generate_roi_table(params):
|
||||
def generate_roi_table(params) -> Dict[str, float]:
|
||||
roi_table = {}
|
||||
roi_table["0"] = params['roi_p1'] + params['roi_p2'] + params['roi_p3']
|
||||
roi_table[str(params['roi_t3'])] = params['roi_p1'] + params['roi_p2']
|
||||
@ -235,7 +235,7 @@ def generate_roi_table(params):
|
||||
return roi_table
|
||||
|
||||
|
||||
def roi_space() -> List[Dict]:
|
||||
def roi_space() -> Dict[str, Any]:
|
||||
return {
|
||||
'roi_t1': hp.quniform('roi_t1', 10, 220, 10),
|
||||
'roi_t2': hp.quniform('roi_t2', 10, 120, 10),
|
||||
@ -246,13 +246,13 @@ def roi_space() -> List[Dict]:
|
||||
}
|
||||
|
||||
|
||||
def stoploss_space() -> Dict:
|
||||
def stoploss_space() -> Dict[str, Any]:
|
||||
return {
|
||||
'stoploss': hp.uniform('stoploss', -0.5, -0.02),
|
||||
}
|
||||
|
||||
|
||||
def indicator_space() -> List[Dict]:
|
||||
def indicator_space() -> Dict[str, Any]:
|
||||
"""
|
||||
Define your Hyperopt space for searching strategy parameters
|
||||
"""
|
||||
@ -312,11 +312,11 @@ def indicator_space() -> List[Dict]:
|
||||
}
|
||||
|
||||
|
||||
def hyperopt_space() -> List[Dict]:
|
||||
def hyperopt_space() -> Dict[str, Any]:
|
||||
return {**indicator_space(), **roi_space(), **stoploss_space()}
|
||||
|
||||
|
||||
def buy_strategy_generator(params) -> None:
|
||||
def buy_strategy_generator(params: Dict[str, Any]) -> Callable:
|
||||
"""
|
||||
Define the buy strategy parameters to be used by hyperopt
|
||||
"""
|
||||
|
@ -193,7 +193,8 @@ def test_backtest_start(default_conf, mocker, caplog):
|
||||
# check the logs, that will contain the backtest result
|
||||
exists = ['Using max_open_trades: 1 ...',
|
||||
'Using stake_amount: 0.001 ...',
|
||||
'Measuring data from 2017-11-14T21:17:00+00:00 up to 2017-11-14T22:59:00+00:00 ...']
|
||||
'Measuring data from 2017-11-14T21:17:00+00:00 '
|
||||
'up to 2017-11-14T22:59:00+00:00 (0 days)..']
|
||||
for line in exists:
|
||||
assert ('freqtrade.optimize.backtesting',
|
||||
logging.INFO,
|
||||
|
@ -2,7 +2,6 @@
|
||||
|
||||
import os
|
||||
import logging
|
||||
# from unittest.mock import MagicMock
|
||||
from shutil import copyfile
|
||||
from freqtrade import exchange, optimize
|
||||
from freqtrade.exchange import Bittrex
|
||||
@ -10,7 +9,7 @@ from freqtrade.optimize.__init__ import make_testdata_path, download_pairs,\
|
||||
download_backtesting_testdata, load_tickerdata_file
|
||||
|
||||
# Change this if modifying BTC_UNITEST testdatafile
|
||||
_btc_unittest_length = 13681
|
||||
_BTC_UNITTEST_LENGTH = 13681
|
||||
|
||||
|
||||
def _backup_file(file: str, copy_file: bool = False) -> None:
|
||||
@ -199,7 +198,7 @@ def test_download_backtesting_testdata(default_conf, ticker_history, mocker):
|
||||
_clean_test_file(file2)
|
||||
|
||||
|
||||
def test_download_backtesting_testdata2(default_conf, mocker):
|
||||
def test_download_backtesting_testdata2(mocker):
|
||||
tick = [{'T': 'bar'}, {'T': 'foo'}]
|
||||
mocker.patch('freqtrade.misc.file_dump_json', return_value=None)
|
||||
mocker.patch('freqtrade.optimize.__init__.get_ticker_history', return_value=tick)
|
||||
@ -210,7 +209,7 @@ def test_download_backtesting_testdata2(default_conf, mocker):
|
||||
def test_load_tickerdata_file():
|
||||
assert not load_tickerdata_file(None, 'BTC_UNITEST', 7)
|
||||
tickerdata = load_tickerdata_file(None, 'BTC_UNITEST', 1)
|
||||
assert _btc_unittest_length == len(tickerdata)
|
||||
assert _BTC_UNITTEST_LENGTH == len(tickerdata)
|
||||
|
||||
|
||||
def test_init(default_conf, mocker):
|
||||
@ -225,4 +224,4 @@ def test_tickerdata_to_dataframe():
|
||||
tick = load_tickerdata_file(None, 'BTC_UNITEST', 1, timerange=timerange)
|
||||
tickerlist = {'BTC_UNITEST': tick}
|
||||
data = optimize.tickerdata_to_dataframe(tickerlist)
|
||||
assert 100 == len(data['BTC_UNITEST'])
|
||||
assert len(data['BTC_UNITEST']) == 100
|
||||
|
@ -1,13 +1,13 @@
|
||||
# pragma pylint: disable=missing-docstring,W0621
|
||||
import datetime
|
||||
import json
|
||||
from unittest.mock import MagicMock
|
||||
import freqtrade.tests.conftest as tt # test tools
|
||||
|
||||
import arrow
|
||||
import datetime
|
||||
import pytest
|
||||
from pandas import DataFrame
|
||||
|
||||
import freqtrade.tests.conftest as tt # test tools
|
||||
from freqtrade.analyze import (get_signal, parse_ticker_dataframe,
|
||||
populate_buy_trend, populate_indicators,
|
||||
populate_sell_trend)
|
||||
|
@ -2,7 +2,6 @@
|
||||
import copy
|
||||
import logging
|
||||
from unittest.mock import MagicMock
|
||||
import freqtrade.tests.conftest as tt # test tools
|
||||
|
||||
import arrow
|
||||
import pytest
|
||||
@ -10,6 +9,7 @@ import requests
|
||||
from sqlalchemy import create_engine
|
||||
|
||||
import freqtrade.main as main
|
||||
import freqtrade.tests.conftest as tt # test tools
|
||||
from freqtrade import DependencyException, OperationalException
|
||||
from freqtrade.exchange import Exchanges
|
||||
from freqtrade.main import (_process, check_handle_timedout, create_trade,
|
||||
@ -50,9 +50,9 @@ def test_main_start_hyperopt(mocker):
|
||||
def test_process_maybe_execute_buy(default_conf, mocker):
|
||||
mocker.patch.dict('freqtrade.main._CONF', default_conf)
|
||||
mocker.patch('freqtrade.main.create_trade', return_value=True)
|
||||
assert main.process_maybe_execute_buy(default_conf, int(default_conf['ticker_interval']))
|
||||
assert main.process_maybe_execute_buy(int(default_conf['ticker_interval']))
|
||||
mocker.patch('freqtrade.main.create_trade', return_value=False)
|
||||
assert not main.process_maybe_execute_buy(default_conf, int(default_conf['ticker_interval']))
|
||||
assert not main.process_maybe_execute_buy(int(default_conf['ticker_interval']))
|
||||
|
||||
|
||||
def test_process_maybe_execute_sell(default_conf, mocker):
|
||||
@ -71,7 +71,7 @@ def test_process_maybe_execute_sell(default_conf, mocker):
|
||||
def test_process_maybe_execute_buy_exception(default_conf, mocker, caplog):
|
||||
mocker.patch.dict('freqtrade.main._CONF', default_conf)
|
||||
mocker.patch('freqtrade.main.create_trade', MagicMock(side_effect=DependencyException))
|
||||
main.process_maybe_execute_buy(default_conf, int(default_conf['ticker_interval']))
|
||||
main.process_maybe_execute_buy(int(default_conf['ticker_interval']))
|
||||
tt.log_has('Unable to create trade:', caplog.record_tuples)
|
||||
|
||||
|
||||
@ -256,7 +256,7 @@ def test_create_trade_no_pairs_after_blacklist(default_conf, ticker, mocker):
|
||||
create_trade(default_conf['stake_amount'], int(default_conf['ticker_interval']))
|
||||
|
||||
|
||||
def test_create_trade_no_signal(default_conf, ticker, mocker):
|
||||
def test_create_trade_no_signal(default_conf, mocker):
|
||||
default_conf['dry_run'] = True
|
||||
mocker.patch.dict('freqtrade.main._CONF', default_conf)
|
||||
mocker.patch('freqtrade.main.get_signal', MagicMock(return_value=(False, False)))
|
||||
@ -308,7 +308,7 @@ def test_handle_trade(default_conf, limit_buy_order, limit_sell_order, mocker):
|
||||
assert trade.close_date is not None
|
||||
|
||||
|
||||
def test_handle_overlpapping_signals(default_conf, ticker, mocker, caplog):
|
||||
def test_handle_overlpapping_signals(default_conf, ticker, mocker):
|
||||
default_conf.update({'experimental': {'use_sell_signal': True}})
|
||||
mocker.patch.dict('freqtrade.main._CONF', default_conf)
|
||||
|
||||
@ -471,7 +471,7 @@ def test_check_handle_timedout_buy(default_conf, ticker, limit_buy_order_old, mo
|
||||
assert len(trades) == 0
|
||||
|
||||
|
||||
def test_handle_timedout_limit_buy(default_conf, mocker):
|
||||
def test_handle_timedout_limit_buy(mocker):
|
||||
cancel_order = MagicMock()
|
||||
mocker.patch('freqtrade.exchange.cancel_order', cancel_order)
|
||||
Trade.session = MagicMock()
|
||||
@ -519,7 +519,7 @@ def test_check_handle_timedout_sell(default_conf, ticker, limit_sell_order_old,
|
||||
assert trade_sell.is_open is True
|
||||
|
||||
|
||||
def test_handle_timedout_limit_sell(default_conf, mocker):
|
||||
def test_handle_timedout_limit_sell(mocker):
|
||||
cancel_order = MagicMock()
|
||||
mocker.patch('freqtrade.exchange.cancel_order', cancel_order)
|
||||
trade = MagicMock()
|
||||
|
@ -3,13 +3,13 @@ import argparse
|
||||
import json
|
||||
import time
|
||||
from copy import deepcopy
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
import pytest
|
||||
from unittest.mock import MagicMock
|
||||
from jsonschema import ValidationError
|
||||
|
||||
from freqtrade.misc import (common_args_parser, load_config, parse_args,
|
||||
throttle, file_dump_json, parse_timerange)
|
||||
from freqtrade.misc import (common_args_parser, file_dump_json, load_config,
|
||||
parse_args, parse_timerange, throttle)
|
||||
|
||||
|
||||
def test_throttle():
|
||||
@ -124,7 +124,7 @@ def test_parse_args_backtesting_custom():
|
||||
assert call_args.refresh_pairs is True
|
||||
|
||||
|
||||
def test_parse_args_hyperopt_custom(mocker):
|
||||
def test_parse_args_hyperopt_custom():
|
||||
args = ['-c', 'test_conf.json', 'hyperopt', '--epochs', '20']
|
||||
call_args = parse_args(args, '')
|
||||
assert call_args.config == 'test_conf.json'
|
||||
@ -134,7 +134,7 @@ def test_parse_args_hyperopt_custom(mocker):
|
||||
assert call_args.func is not None
|
||||
|
||||
|
||||
def test_file_dump_json(default_conf, mocker):
|
||||
def test_file_dump_json(mocker):
|
||||
file_open = mocker.patch('freqtrade.misc.open', MagicMock())
|
||||
json_dump = mocker.patch('json.dump', MagicMock())
|
||||
file_dump_json('somefile', [1, 2, 3])
|
||||
|
Loading…
Reference in New Issue
Block a user