commit
dde0695909
@ -1,12 +1,19 @@
|
|||||||
|
"""
|
||||||
|
Module that define classes to convert Crypto-currency to FIAT
|
||||||
|
e.g BTC to USD
|
||||||
|
"""
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
import time
|
import time
|
||||||
|
|
||||||
from pymarketcap import Pymarketcap
|
from pymarketcap import Pymarketcap
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class CryptoFiat():
|
class CryptoFiat():
|
||||||
|
"""
|
||||||
|
Object to describe what is the price of Crypto-currency in a FIAT
|
||||||
|
"""
|
||||||
# Constants
|
# Constants
|
||||||
CACHE_DURATION = 6 * 60 * 60 # 6 hours
|
CACHE_DURATION = 6 * 60 * 60 # 6 hours
|
||||||
|
|
||||||
@ -49,6 +56,11 @@ class CryptoFiat():
|
|||||||
|
|
||||||
|
|
||||||
class CryptoToFiatConverter(object):
|
class CryptoToFiatConverter(object):
|
||||||
|
"""
|
||||||
|
Main class to initiate Crypto to FIAT.
|
||||||
|
This object contains a list of pair Crypto, FIAT
|
||||||
|
This object is also a Singleton
|
||||||
|
"""
|
||||||
__instance = None
|
__instance = None
|
||||||
_coinmarketcap = None
|
_coinmarketcap = None
|
||||||
|
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
|
# pragma pylint: disable=missing-docstring, invalid-name, pointless-string-statement
|
||||||
|
|
||||||
import talib.abstract as ta
|
import talib.abstract as ta
|
||||||
|
from pandas import DataFrame
|
||||||
import freqtrade.vendor.qtpylib.indicators as qtpylib
|
import freqtrade.vendor.qtpylib.indicators as qtpylib
|
||||||
from freqtrade.strategy.interface import IStrategy
|
from freqtrade.strategy.interface import IStrategy
|
||||||
from pandas import DataFrame
|
|
||||||
|
|
||||||
|
|
||||||
class_name = 'DefaultStrategy'
|
class_name = 'DefaultStrategy'
|
||||||
|
@ -1,8 +1,22 @@
|
|||||||
|
"""
|
||||||
|
IStrategy interface
|
||||||
|
This module defines the interface to apply for strategies
|
||||||
|
"""
|
||||||
|
|
||||||
from abc import ABC, abstractmethod
|
from abc import ABC, abstractmethod
|
||||||
from pandas import DataFrame
|
from pandas import DataFrame
|
||||||
|
|
||||||
|
|
||||||
class IStrategy(ABC):
|
class IStrategy(ABC):
|
||||||
|
"""
|
||||||
|
Interface for freqtrade strategies
|
||||||
|
Defines the mandatory structure must follow any custom strategies
|
||||||
|
|
||||||
|
Attributes you can use:
|
||||||
|
minimal_roi -> Dict: Minimal ROI designed for the strategy
|
||||||
|
stoploss -> float: optimal stoploss designed for the strategy
|
||||||
|
ticker_interval -> int: value of the ticker interval to use for the strategy
|
||||||
|
"""
|
||||||
@property
|
@property
|
||||||
def name(self) -> str:
|
def name(self) -> str:
|
||||||
"""
|
"""
|
||||||
@ -11,13 +25,6 @@ class IStrategy(ABC):
|
|||||||
"""
|
"""
|
||||||
return self.__class__.__name__
|
return self.__class__.__name__
|
||||||
|
|
||||||
"""
|
|
||||||
Attributes you can use:
|
|
||||||
minimal_roi -> Dict: Minimal ROI designed for the strategy
|
|
||||||
stoploss -> float: optimal stoploss designed for the strategy
|
|
||||||
ticker_interval -> int: value of the ticker interval to use for the strategy
|
|
||||||
"""
|
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def populate_indicators(self, dataframe: DataFrame) -> DataFrame:
|
def populate_indicators(self, dataframe: DataFrame) -> DataFrame:
|
||||||
"""
|
"""
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
|
"""
|
||||||
|
This module load custom strategies
|
||||||
|
"""
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import logging
|
import logging
|
||||||
import importlib
|
import importlib
|
||||||
|
|
||||||
from pandas import DataFrame
|
from pandas import DataFrame
|
||||||
from typing import Dict
|
|
||||||
from freqtrade.strategy.interface import IStrategy
|
from freqtrade.strategy.interface import IStrategy
|
||||||
|
|
||||||
|
|
||||||
@ -12,16 +14,36 @@ sys.path.insert(0, r'../../user_data/strategies')
|
|||||||
|
|
||||||
|
|
||||||
class Strategy(object):
|
class Strategy(object):
|
||||||
|
"""
|
||||||
|
This class contains all the logic to load custom strategy class
|
||||||
|
"""
|
||||||
__instance = None
|
__instance = None
|
||||||
|
|
||||||
DEFAULT_STRATEGY = 'default_strategy'
|
DEFAULT_STRATEGY = 'default_strategy'
|
||||||
|
|
||||||
def __new__(cls):
|
def __new__(cls):
|
||||||
|
"""
|
||||||
|
Used to create the Singleton
|
||||||
|
:return: Strategy object
|
||||||
|
"""
|
||||||
if Strategy.__instance is None:
|
if Strategy.__instance is None:
|
||||||
Strategy.__instance = object.__new__(cls)
|
Strategy.__instance = object.__new__(cls)
|
||||||
return Strategy.__instance
|
return Strategy.__instance
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
if Strategy.__instance is None:
|
||||||
|
self.logger = None
|
||||||
|
self.minimal_roi = None
|
||||||
|
self.stoploss = None
|
||||||
|
self.ticker_interval = None
|
||||||
|
self.custom_strategy = None
|
||||||
|
|
||||||
def init(self, config):
|
def init(self, config):
|
||||||
|
"""
|
||||||
|
Load the custom class from config parameter
|
||||||
|
:param config:
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
self.logger = logging.getLogger(__name__)
|
self.logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
# Verify the strategy is in the configuration, otherwise fallback to the default strategy
|
# Verify the strategy is in the configuration, otherwise fallback to the default strategy
|
||||||
@ -42,21 +64,22 @@ class Strategy(object):
|
|||||||
if 'stoploss' in config:
|
if 'stoploss' in config:
|
||||||
self.custom_strategy.stoploss = config['stoploss']
|
self.custom_strategy.stoploss = config['stoploss']
|
||||||
self.logger.info(
|
self.logger.info(
|
||||||
"Override strategy \'stoploss\' with value in config file: {}.".format(
|
"Override strategy \'stoploss\' with value in config file: %s.", config['stoploss']
|
||||||
config['stoploss']
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
if 'ticker_interval' in config:
|
if 'ticker_interval' in config:
|
||||||
self.custom_strategy.ticker_interval = config['ticker_interval']
|
self.custom_strategy.ticker_interval = config['ticker_interval']
|
||||||
self.logger.info(
|
self.logger.info(
|
||||||
"Override strategy \'ticker_interval\' with value in config file: {}.".format(
|
"Override strategy \'ticker_interval\' with value in config file: %s.",
|
||||||
config['ticker_interval']
|
config['ticker_interval']
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Minimal ROI designed for the strategy
|
||||||
self.minimal_roi = self.custom_strategy.minimal_roi
|
self.minimal_roi = self.custom_strategy.minimal_roi
|
||||||
|
|
||||||
|
# Optimal stoploss designed for the strategy
|
||||||
self.stoploss = self.custom_strategy.stoploss
|
self.stoploss = self.custom_strategy.stoploss
|
||||||
|
|
||||||
self.ticker_interval = self.custom_strategy.ticker_interval
|
self.ticker_interval = self.custom_strategy.ticker_interval
|
||||||
|
|
||||||
def _load_strategy(self, strategy_name: str) -> None:
|
def _load_strategy(self, strategy_name: str) -> None:
|
||||||
@ -90,7 +113,7 @@ class Strategy(object):
|
|||||||
module = importlib.import_module(filename, __package__)
|
module = importlib.import_module(filename, __package__)
|
||||||
custom_strategy = getattr(module, module.class_name)
|
custom_strategy = getattr(module, module.class_name)
|
||||||
|
|
||||||
self.logger.info("Load strategy class: {} ({}.py)".format(module.class_name, filename))
|
self.logger.info("Load strategy class: %s (%s.py)", module.class_name, filename)
|
||||||
return custom_strategy()
|
return custom_strategy()
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@ -126,20 +149,6 @@ class Strategy(object):
|
|||||||
|
|
||||||
return path
|
return path
|
||||||
|
|
||||||
def minimal_roi(self) -> Dict:
|
|
||||||
"""
|
|
||||||
Minimal ROI designed for the strategy
|
|
||||||
:return: Dict: Value for the Minimal ROI
|
|
||||||
"""
|
|
||||||
return
|
|
||||||
|
|
||||||
def stoploss(self) -> float:
|
|
||||||
"""
|
|
||||||
Optimal stoploss designed for the strategy
|
|
||||||
:return: float | return None to disable it
|
|
||||||
"""
|
|
||||||
return self.custom_strategy.stoploss
|
|
||||||
|
|
||||||
def populate_indicators(self, dataframe: DataFrame) -> DataFrame:
|
def populate_indicators(self, dataframe: DataFrame) -> DataFrame:
|
||||||
"""
|
"""
|
||||||
Populate indicators that will be used in the Buy and Sell strategy
|
Populate indicators that will be used in the Buy and Sell strategy
|
||||||
|
@ -3,10 +3,13 @@ from datetime import datetime
|
|||||||
from unittest.mock import MagicMock
|
from unittest.mock import MagicMock
|
||||||
from functools import reduce
|
from functools import reduce
|
||||||
|
|
||||||
|
import json
|
||||||
import arrow
|
import arrow
|
||||||
import pytest
|
import pytest
|
||||||
from jsonschema import validate
|
from jsonschema import validate
|
||||||
from telegram import Chat, Message, Update
|
from telegram import Chat, Message, Update
|
||||||
|
from freqtrade.analyze import parse_ticker_dataframe
|
||||||
|
from freqtrade.strategy.strategy import Strategy
|
||||||
|
|
||||||
from freqtrade.misc import CONF_SCHEMA
|
from freqtrade.misc import CONF_SCHEMA
|
||||||
|
|
||||||
@ -256,3 +259,16 @@ def ticker_history_without_bv():
|
|||||||
"T": "2017-11-26T09:00:00"
|
"T": "2017-11-26T09:00:00"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def result():
|
||||||
|
with open('freqtrade/tests/testdata/BTC_ETH-1.json') as data_file:
|
||||||
|
return parse_ticker_dataframe(json.load(data_file))
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def default_strategy():
|
||||||
|
strategy = Strategy()
|
||||||
|
strategy.init({'strategy': 'default_strategy'})
|
||||||
|
return strategy
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
# pragma pylint: disable=missing-docstring,C0103
|
# pragma pylint: disable=missing-docstring, C0103, bad-continuation, global-statement
|
||||||
|
# pragma pylint: disable=protected-access
|
||||||
from unittest.mock import MagicMock
|
from unittest.mock import MagicMock
|
||||||
from requests.exceptions import RequestException
|
|
||||||
from random import randint
|
from random import randint
|
||||||
import logging
|
import logging
|
||||||
|
from requests.exceptions import RequestException
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from freqtrade import OperationalException
|
from freqtrade import OperationalException
|
||||||
@ -30,7 +31,7 @@ def test_init(default_conf, mocker, caplog):
|
|||||||
) in caplog.record_tuples
|
) in caplog.record_tuples
|
||||||
|
|
||||||
|
|
||||||
def test_init_exception(default_conf, mocker):
|
def test_init_exception(default_conf):
|
||||||
default_conf['exchange']['name'] = 'wrong_exchange_name'
|
default_conf['exchange']['name'] = 'wrong_exchange_name'
|
||||||
|
|
||||||
with pytest.raises(
|
with pytest.raises(
|
||||||
@ -171,7 +172,7 @@ def test_get_balances_prod(default_conf, mocker):
|
|||||||
|
|
||||||
# This test is somewhat redundant with
|
# This test is somewhat redundant with
|
||||||
# test_exchange_bittrex.py::test_exchange_bittrex_get_ticker
|
# test_exchange_bittrex.py::test_exchange_bittrex_get_ticker
|
||||||
def test_get_ticker(default_conf, mocker, ticker):
|
def test_get_ticker(default_conf, mocker):
|
||||||
maybe_init_api(default_conf, mocker)
|
maybe_init_api(default_conf, mocker)
|
||||||
api_mock = MagicMock()
|
api_mock = MagicMock()
|
||||||
tick = {"success": True, 'result': {'Bid': 0.00001098, 'Ask': 0.00001099, 'Last': 0.0001}}
|
tick = {"success": True, 'result': {'Bid': 0.00001098, 'Ask': 0.00001099, 'Last': 0.0001}}
|
||||||
@ -200,7 +201,7 @@ def test_get_ticker(default_conf, mocker, ticker):
|
|||||||
assert ticker['ask'] == 1
|
assert ticker['ask'] == 1
|
||||||
|
|
||||||
|
|
||||||
def test_get_ticker_history(default_conf, mocker, ticker):
|
def test_get_ticker_history(default_conf, mocker):
|
||||||
api_mock = MagicMock()
|
api_mock = MagicMock()
|
||||||
tick = 123
|
tick = 123
|
||||||
api_mock.get_ticker_history = MagicMock(return_value=tick)
|
api_mock.get_ticker_history = MagicMock(return_value=tick)
|
||||||
@ -251,7 +252,7 @@ def test_get_order(default_conf, mocker):
|
|||||||
api_mock = MagicMock()
|
api_mock = MagicMock()
|
||||||
api_mock.get_order = MagicMock(return_value=456)
|
api_mock.get_order = MagicMock(return_value=456)
|
||||||
mocker.patch('freqtrade.exchange._API', api_mock)
|
mocker.patch('freqtrade.exchange._API', api_mock)
|
||||||
assert 456 == exchange.get_order('X')
|
assert exchange.get_order('X') == 456
|
||||||
|
|
||||||
|
|
||||||
def test_get_name(default_conf, mocker):
|
def test_get_name(default_conf, mocker):
|
||||||
@ -271,16 +272,16 @@ def test_get_fee(default_conf, mocker):
|
|||||||
assert get_fee() == 0.0025
|
assert get_fee() == 0.0025
|
||||||
|
|
||||||
|
|
||||||
def test_exchange_misc(default_conf, mocker):
|
def test_exchange_misc(mocker):
|
||||||
api_mock = MagicMock()
|
api_mock = MagicMock()
|
||||||
mocker.patch('freqtrade.exchange._API', api_mock)
|
mocker.patch('freqtrade.exchange._API', api_mock)
|
||||||
exchange.get_markets()
|
exchange.get_markets()
|
||||||
assert 1 == api_mock.get_markets.call_count
|
assert api_mock.get_markets.call_count == 1
|
||||||
exchange.get_market_summaries()
|
exchange.get_market_summaries()
|
||||||
assert 1 == api_mock.get_market_summaries.call_count
|
assert api_mock.get_market_summaries.call_count == 1
|
||||||
api_mock.name = 123
|
api_mock.name = 123
|
||||||
assert 123 == exchange.get_name()
|
assert exchange.get_name() == 123
|
||||||
api_mock.fee = 456
|
api_mock.fee = 456
|
||||||
assert 456 == exchange.get_fee()
|
assert exchange.get_fee() == 456
|
||||||
exchange.get_wallet_health()
|
exchange.get_wallet_health()
|
||||||
assert 1 == api_mock.get_wallet_health.call_count
|
assert api_mock.get_wallet_health.call_count == 1
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
# pragma pylint: disable=missing-docstring,C0103
|
# pragma pylint: disable=missing-docstring, C0103, protected-access, unused-argument
|
||||||
|
|
||||||
import pytest
|
|
||||||
from unittest.mock import MagicMock
|
from unittest.mock import MagicMock
|
||||||
|
import pytest
|
||||||
from requests.exceptions import ContentDecodingError
|
from requests.exceptions import ContentDecodingError
|
||||||
|
|
||||||
from freqtrade.exchange.bittrex import Bittrex
|
from freqtrade.exchange.bittrex import Bittrex
|
||||||
import freqtrade.exchange.bittrex as btx
|
import freqtrade.exchange.bittrex as btx
|
||||||
|
|
||||||
@ -88,8 +87,7 @@ class FakeBittrex():
|
|||||||
'PricePerUnit': 1,
|
'PricePerUnit': 1,
|
||||||
'Quantity': 1,
|
'Quantity': 1,
|
||||||
'QuantityRemaining': 1,
|
'QuantityRemaining': 1,
|
||||||
'Closed': True
|
'Closed': True},
|
||||||
},
|
|
||||||
'message': 'lost'}
|
'message': 'lost'}
|
||||||
|
|
||||||
def fake_cancel_order(self, uuid):
|
def fake_cancel_order(self, uuid):
|
||||||
@ -211,24 +209,18 @@ def test_exchange_bittrex_get_ticker():
|
|||||||
def test_exchange_bittrex_get_ticker_bad():
|
def test_exchange_bittrex_get_ticker_bad():
|
||||||
wb = make_wrap_bittrex()
|
wb = make_wrap_bittrex()
|
||||||
fb = FakeBittrex()
|
fb = FakeBittrex()
|
||||||
fb.result = {'success': True,
|
fb.result = {'success': True, 'result': {'Bid': 1, 'Ask': 0}} # incomplete result
|
||||||
'result': {'Bid': 1, 'Ask': 0}} # incomplete result
|
|
||||||
|
|
||||||
with pytest.raises(ContentDecodingError, match=r'.*Got invalid response from bittrex params.*'):
|
with pytest.raises(ContentDecodingError, match=r'.*Got invalid response from bittrex params.*'):
|
||||||
wb.get_ticker('BTC_ETH')
|
wb.get_ticker('BTC_ETH')
|
||||||
fb.result = {'success': False,
|
fb.result = {'success': False, 'message': 'gone bad'}
|
||||||
'message': 'gone bad'
|
|
||||||
}
|
|
||||||
with pytest.raises(btx.OperationalException, match=r'.*gone bad.*'):
|
with pytest.raises(btx.OperationalException, match=r'.*gone bad.*'):
|
||||||
wb.get_ticker('BTC_ETH')
|
wb.get_ticker('BTC_ETH')
|
||||||
|
|
||||||
fb.result = {'success': True,
|
fb.result = {'success': True, 'result': {}} # incomplete result
|
||||||
'result': {}} # incomplete result
|
|
||||||
with pytest.raises(ContentDecodingError, match=r'.*Got invalid response from bittrex params.*'):
|
with pytest.raises(ContentDecodingError, match=r'.*Got invalid response from bittrex params.*'):
|
||||||
wb.get_ticker('BTC_ETH')
|
wb.get_ticker('BTC_ETH')
|
||||||
fb.result = {'success': False,
|
fb.result = {'success': False, 'message': 'gone bad'}
|
||||||
'message': 'gone bad'
|
|
||||||
}
|
|
||||||
with pytest.raises(btx.OperationalException, match=r'.*gone bad.*'):
|
with pytest.raises(btx.OperationalException, match=r'.*gone bad.*'):
|
||||||
wb.get_ticker('BTC_ETH')
|
wb.get_ticker('BTC_ETH')
|
||||||
|
|
||||||
|
@ -1,28 +1,19 @@
|
|||||||
# pragma pylint: disable=missing-docstring,W0212
|
# pragma pylint: disable=missing-docstring, W0212, line-too-long, C0103
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
import math
|
import math
|
||||||
import pandas as pd
|
|
||||||
import pytest
|
|
||||||
from unittest.mock import MagicMock
|
from unittest.mock import MagicMock
|
||||||
|
import pandas as pd
|
||||||
from freqtrade import exchange, optimize
|
from freqtrade import exchange, optimize
|
||||||
from freqtrade.exchange import Bittrex
|
from freqtrade.exchange import Bittrex
|
||||||
from freqtrade.optimize import preprocess
|
from freqtrade.optimize import preprocess
|
||||||
from freqtrade.optimize.backtesting import backtest, generate_text_table, get_timeframe
|
from freqtrade.optimize.backtesting import backtest, generate_text_table, get_timeframe
|
||||||
import freqtrade.optimize.backtesting as backtesting
|
import freqtrade.optimize.backtesting as backtesting
|
||||||
from freqtrade.strategy.strategy import Strategy
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
def trim_dictlist(dict_list, num):
|
||||||
def default_strategy():
|
|
||||||
strategy = Strategy()
|
|
||||||
strategy.init({'strategy': 'default_strategy'})
|
|
||||||
return strategy
|
|
||||||
|
|
||||||
|
|
||||||
def trim_dictlist(dl, num):
|
|
||||||
new = {}
|
new = {}
|
||||||
for pair, pair_data in dl.items():
|
for pair, pair_data in dict_list.items():
|
||||||
new[pair] = pair_data[num:]
|
new[pair] = pair_data[num:]
|
||||||
return new
|
return new
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
# pragma pylint: disable=missing-docstring,W0212
|
# pragma pylint: disable=missing-docstring, protected-access, C0103
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import logging
|
import logging
|
||||||
@ -55,8 +55,7 @@ def test_load_data_30min_ticker(default_conf, ticker_history, mocker, caplog):
|
|||||||
assert os.path.isfile(file) is True
|
assert os.path.isfile(file) is True
|
||||||
assert ('freqtrade.optimize',
|
assert ('freqtrade.optimize',
|
||||||
logging.INFO,
|
logging.INFO,
|
||||||
'Download the pair: "BTC_ETH", Interval: 30 min'
|
'Download the pair: "BTC_ETH", Interval: 30 min') not in caplog.record_tuples
|
||||||
) not in caplog.record_tuples
|
|
||||||
_clean_test_file(file)
|
_clean_test_file(file)
|
||||||
|
|
||||||
|
|
||||||
@ -72,8 +71,7 @@ def test_load_data_5min_ticker(default_conf, ticker_history, mocker, caplog):
|
|||||||
assert os.path.isfile(file) is True
|
assert os.path.isfile(file) is True
|
||||||
assert ('freqtrade.optimize',
|
assert ('freqtrade.optimize',
|
||||||
logging.INFO,
|
logging.INFO,
|
||||||
'Download the pair: "BTC_ETH", Interval: 5 min'
|
'Download the pair: "BTC_ETH", Interval: 5 min') not in caplog.record_tuples
|
||||||
) not in caplog.record_tuples
|
|
||||||
_clean_test_file(file)
|
_clean_test_file(file)
|
||||||
|
|
||||||
|
|
||||||
@ -89,8 +87,7 @@ def test_load_data_1min_ticker(default_conf, ticker_history, mocker, caplog):
|
|||||||
assert os.path.isfile(file) is True
|
assert os.path.isfile(file) is True
|
||||||
assert ('freqtrade.optimize',
|
assert ('freqtrade.optimize',
|
||||||
logging.INFO,
|
logging.INFO,
|
||||||
'Download the pair: "BTC_ETH", Interval: 1 min'
|
'Download the pair: "BTC_ETH", Interval: 1 min') not in caplog.record_tuples
|
||||||
) not in caplog.record_tuples
|
|
||||||
_clean_test_file(file)
|
_clean_test_file(file)
|
||||||
|
|
||||||
|
|
||||||
@ -106,8 +103,7 @@ def test_load_data_with_new_pair_1min(default_conf, ticker_history, mocker, capl
|
|||||||
assert os.path.isfile(file) is True
|
assert os.path.isfile(file) is True
|
||||||
assert ('freqtrade.optimize',
|
assert ('freqtrade.optimize',
|
||||||
logging.INFO,
|
logging.INFO,
|
||||||
'Download the pair: "BTC_MEME", Interval: 1 min'
|
'Download the pair: "BTC_MEME", Interval: 1 min') in caplog.record_tuples
|
||||||
) in caplog.record_tuples
|
|
||||||
_clean_test_file(file)
|
_clean_test_file(file)
|
||||||
|
|
||||||
|
|
||||||
@ -173,8 +169,7 @@ def test_download_pairs_exception(default_conf, ticker_history, mocker, caplog):
|
|||||||
_clean_test_file(file1_5)
|
_clean_test_file(file1_5)
|
||||||
assert ('freqtrade.optimize.__init__',
|
assert ('freqtrade.optimize.__init__',
|
||||||
logging.INFO,
|
logging.INFO,
|
||||||
'Failed to download the pair: "BTC-MEME", Interval: 1 min'
|
'Failed to download the pair: "BTC-MEME", Interval: 1 min') in caplog.record_tuples
|
||||||
) in caplog.record_tuples
|
|
||||||
|
|
||||||
|
|
||||||
def test_download_backtesting_testdata(default_conf, ticker_history, mocker):
|
def test_download_backtesting_testdata(default_conf, ticker_history, mocker):
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
# pragma pylint: disable=missing-docstring, too-many-arguments, too-many-ancestors, C0103
|
# pragma pylint: disable=missing-docstring, too-many-arguments, too-many-ancestors, C0103
|
||||||
|
# pragma pylint: disable=unused-argument
|
||||||
import re
|
import re
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from random import randint
|
from random import randint
|
||||||
|
@ -1,14 +1,7 @@
|
|||||||
import json
|
# pragma pylint: disable=missing-docstring, protected-access, C0103
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
import pytest
|
|
||||||
from freqtrade.strategy.strategy import Strategy
|
from freqtrade.strategy.strategy import Strategy
|
||||||
from freqtrade.analyze import parse_ticker_dataframe
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def result():
|
|
||||||
with open('freqtrade/tests/testdata/BTC_ETH-1.json') as data_file:
|
|
||||||
return parse_ticker_dataframe(json.load(data_file))
|
|
||||||
|
|
||||||
|
|
||||||
def test_sanitize_module_name():
|
def test_sanitize_module_name():
|
||||||
@ -28,8 +21,6 @@ def test_search_strategy():
|
|||||||
|
|
||||||
def test_strategy_structure():
|
def test_strategy_structure():
|
||||||
assert hasattr(Strategy, 'init')
|
assert hasattr(Strategy, 'init')
|
||||||
assert hasattr(Strategy, 'minimal_roi')
|
|
||||||
assert hasattr(Strategy, 'stoploss')
|
|
||||||
assert hasattr(Strategy, 'populate_indicators')
|
assert hasattr(Strategy, 'populate_indicators')
|
||||||
assert hasattr(Strategy, 'populate_buy_trend')
|
assert hasattr(Strategy, 'populate_buy_trend')
|
||||||
assert hasattr(Strategy, 'populate_sell_trend')
|
assert hasattr(Strategy, 'populate_sell_trend')
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
# pragma pylint: disable=missing-docstring,C0103
|
||||||
|
|
||||||
from freqtrade.main import refresh_whitelist, gen_pair_whitelist
|
from freqtrade.main import refresh_whitelist, gen_pair_whitelist
|
||||||
|
|
||||||
# whitelist, blacklist, filtering, all of that will
|
# whitelist, blacklist, filtering, all of that will
|
||||||
@ -73,16 +75,9 @@ def get_market_summaries():
|
|||||||
|
|
||||||
|
|
||||||
def get_health():
|
def get_health():
|
||||||
return [{'Currency': 'ETH',
|
return [{'Currency': 'ETH', 'IsActive': True},
|
||||||
'IsActive': True
|
{'Currency': 'TKN', 'IsActive': True},
|
||||||
},
|
{'Currency': 'BLK', 'IsActive': True}]
|
||||||
{'Currency': 'TKN',
|
|
||||||
'IsActive': True
|
|
||||||
},
|
|
||||||
{'Currency': 'BLK',
|
|
||||||
'IsActive': True
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
def get_health_empty():
|
def get_health_empty():
|
||||||
|
@ -1,10 +1,8 @@
|
|||||||
# pragma pylint: disable=missing-docstring,W0621
|
# pragma pylint: disable=missing-docstring, C0103
|
||||||
import datetime
|
import datetime
|
||||||
import json
|
|
||||||
from unittest.mock import MagicMock
|
from unittest.mock import MagicMock
|
||||||
|
|
||||||
import arrow
|
import arrow
|
||||||
import pytest
|
|
||||||
from pandas import DataFrame
|
from pandas import DataFrame
|
||||||
|
|
||||||
import freqtrade.tests.conftest as tt # test tools
|
import freqtrade.tests.conftest as tt # test tools
|
||||||
@ -14,12 +12,6 @@ from freqtrade.analyze import (get_signal, parse_ticker_dataframe,
|
|||||||
from freqtrade.strategy.strategy import Strategy
|
from freqtrade.strategy.strategy import Strategy
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def result():
|
|
||||||
with open('freqtrade/tests/testdata/BTC_ETH-1.json') as data_file:
|
|
||||||
return parse_ticker_dataframe(json.load(data_file))
|
|
||||||
|
|
||||||
|
|
||||||
def test_dataframe_correct_columns(result):
|
def test_dataframe_correct_columns(result):
|
||||||
assert result.columns.tolist() == \
|
assert result.columns.tolist() == \
|
||||||
['close', 'high', 'low', 'open', 'date', 'volume']
|
['close', 'high', 'low', 'open', 'date', 'volume']
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import pandas
|
# pragma pylint: disable=missing-docstring, C0103
|
||||||
|
|
||||||
|
import pandas
|
||||||
import freqtrade.optimize
|
import freqtrade.optimize
|
||||||
from freqtrade import analyze
|
from freqtrade import analyze
|
||||||
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
# pragma pylint: disable=missing-docstring, too-many-arguments, too-many-ancestors, C0103
|
# pragma pylint: disable=missing-docstring, too-many-arguments, too-many-ancestors,
|
||||||
|
# pragma pylint: disable=protected-access, C0103
|
||||||
|
|
||||||
import time
|
import time
|
||||||
from unittest.mock import MagicMock
|
from unittest.mock import MagicMock
|
||||||
@ -47,16 +48,19 @@ def test_fiat_convert_is_supported():
|
|||||||
def test_fiat_convert_add_pair():
|
def test_fiat_convert_add_pair():
|
||||||
fiat_convert = CryptoToFiatConverter()
|
fiat_convert = CryptoToFiatConverter()
|
||||||
|
|
||||||
assert len(fiat_convert._pairs) == 0
|
pair_len = len(fiat_convert._pairs)
|
||||||
|
assert pair_len == 0
|
||||||
|
|
||||||
fiat_convert._add_pair(crypto_symbol='btc', fiat_symbol='usd', price=12345.0)
|
fiat_convert._add_pair(crypto_symbol='btc', fiat_symbol='usd', price=12345.0)
|
||||||
assert len(fiat_convert._pairs) == 1
|
pair_len = len(fiat_convert._pairs)
|
||||||
|
assert pair_len == 1
|
||||||
assert fiat_convert._pairs[0].crypto_symbol == 'BTC'
|
assert fiat_convert._pairs[0].crypto_symbol == 'BTC'
|
||||||
assert fiat_convert._pairs[0].fiat_symbol == 'USD'
|
assert fiat_convert._pairs[0].fiat_symbol == 'USD'
|
||||||
assert fiat_convert._pairs[0].price == 12345.0
|
assert fiat_convert._pairs[0].price == 12345.0
|
||||||
|
|
||||||
fiat_convert._add_pair(crypto_symbol='btc', fiat_symbol='Eur', price=13000.2)
|
fiat_convert._add_pair(crypto_symbol='btc', fiat_symbol='Eur', price=13000.2)
|
||||||
assert len(fiat_convert._pairs) == 2
|
pair_len = len(fiat_convert._pairs)
|
||||||
|
assert pair_len == 2
|
||||||
assert fiat_convert._pairs[1].crypto_symbol == 'BTC'
|
assert fiat_convert._pairs[1].crypto_symbol == 'BTC'
|
||||||
assert fiat_convert._pairs[1].fiat_symbol == 'EUR'
|
assert fiat_convert._pairs[1].fiat_symbol == 'EUR'
|
||||||
assert fiat_convert._pairs[1].price == 13000.2
|
assert fiat_convert._pairs[1].price == 13000.2
|
||||||
@ -95,7 +99,8 @@ def test_fiat_convert_get_price(mocker):
|
|||||||
fiat_convert.get_price(crypto_symbol='BTC', fiat_symbol='US Dollar')
|
fiat_convert.get_price(crypto_symbol='BTC', fiat_symbol='US Dollar')
|
||||||
|
|
||||||
# Check the value return by the method
|
# Check the value return by the method
|
||||||
assert len(fiat_convert._pairs) == 0
|
pair_len = len(fiat_convert._pairs)
|
||||||
|
assert pair_len == 0
|
||||||
assert fiat_convert.get_price(crypto_symbol='BTC', fiat_symbol='USD') == 28000.0
|
assert fiat_convert.get_price(crypto_symbol='BTC', fiat_symbol='USD') == 28000.0
|
||||||
assert fiat_convert._pairs[0].crypto_symbol == 'BTC'
|
assert fiat_convert._pairs[0].crypto_symbol == 'BTC'
|
||||||
assert fiat_convert._pairs[0].fiat_symbol == 'USD'
|
assert fiat_convert._pairs[0].fiat_symbol == 'USD'
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
# pragma pylint: disable=missing-docstring,C0103
|
# pragma pylint: disable=missing-docstring, C0103
|
||||||
import copy
|
import copy
|
||||||
import logging
|
import logging
|
||||||
from unittest.mock import MagicMock
|
from unittest.mock import MagicMock
|
||||||
@ -325,27 +325,31 @@ def test_handle_overlpapping_signals(default_conf, ticker, mocker):
|
|||||||
|
|
||||||
# Buy and Sell triggering, so doing nothing ...
|
# Buy and Sell triggering, so doing nothing ...
|
||||||
trades = Trade.query.all()
|
trades = Trade.query.all()
|
||||||
assert len(trades) == 0
|
nb_trades = len(trades)
|
||||||
|
assert nb_trades == 0
|
||||||
|
|
||||||
# Buy is triggering, so buying ...
|
# Buy is triggering, so buying ...
|
||||||
mocker.patch('freqtrade.main.get_signal', side_effect=lambda s, t: (True, False))
|
mocker.patch('freqtrade.main.get_signal', side_effect=lambda s, t: (True, False))
|
||||||
create_trade(0.001, int(default_conf['ticker_interval']))
|
create_trade(0.001, int(default_conf['ticker_interval']))
|
||||||
trades = Trade.query.all()
|
trades = Trade.query.all()
|
||||||
assert len(trades) == 1
|
nb_trades = len(trades)
|
||||||
|
assert nb_trades == 1
|
||||||
assert trades[0].is_open is True
|
assert trades[0].is_open is True
|
||||||
|
|
||||||
# Buy and Sell are not triggering, so doing nothing ...
|
# Buy and Sell are not triggering, so doing nothing ...
|
||||||
mocker.patch('freqtrade.main.get_signal', side_effect=lambda s, t: (False, False))
|
mocker.patch('freqtrade.main.get_signal', side_effect=lambda s, t: (False, False))
|
||||||
assert handle_trade(trades[0], int(default_conf['ticker_interval'])) is False
|
assert handle_trade(trades[0], int(default_conf['ticker_interval'])) is False
|
||||||
trades = Trade.query.all()
|
trades = Trade.query.all()
|
||||||
assert len(trades) == 1
|
nb_trades = len(trades)
|
||||||
|
assert nb_trades == 1
|
||||||
assert trades[0].is_open is True
|
assert trades[0].is_open is True
|
||||||
|
|
||||||
# Buy and Sell are triggering, so doing nothing ...
|
# Buy and Sell are triggering, so doing nothing ...
|
||||||
mocker.patch('freqtrade.main.get_signal', side_effect=lambda s, t: (True, True))
|
mocker.patch('freqtrade.main.get_signal', side_effect=lambda s, t: (True, True))
|
||||||
assert handle_trade(trades[0], int(default_conf['ticker_interval'])) is False
|
assert handle_trade(trades[0], int(default_conf['ticker_interval'])) is False
|
||||||
trades = Trade.query.all()
|
trades = Trade.query.all()
|
||||||
assert len(trades) == 1
|
nb_trades = len(trades)
|
||||||
|
assert nb_trades == 1
|
||||||
assert trades[0].is_open is True
|
assert trades[0].is_open is True
|
||||||
|
|
||||||
# Sell is triggering, guess what : we are Selling!
|
# Sell is triggering, guess what : we are Selling!
|
||||||
@ -468,7 +472,8 @@ def test_check_handle_timedout_buy(default_conf, ticker, limit_buy_order_old, mo
|
|||||||
assert cancel_order_mock.call_count == 1
|
assert cancel_order_mock.call_count == 1
|
||||||
assert rpc_mock.call_count == 1
|
assert rpc_mock.call_count == 1
|
||||||
trades = Trade.query.filter(Trade.open_order_id.is_(trade_buy.open_order_id)).all()
|
trades = Trade.query.filter(Trade.open_order_id.is_(trade_buy.open_order_id)).all()
|
||||||
assert len(trades) == 0
|
nb_trades = len(trades)
|
||||||
|
assert nb_trades == 0
|
||||||
|
|
||||||
|
|
||||||
def test_handle_timedout_limit_buy(mocker):
|
def test_handle_timedout_limit_buy(mocker):
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
# pragma pylint: disable=missing-docstring
|
# pragma pylint: disable=missing-docstring, C0103
|
||||||
import os
|
import os
|
||||||
import pytest
|
import pytest
|
||||||
from sqlalchemy import create_engine
|
from sqlalchemy import create_engine
|
||||||
@ -12,7 +12,7 @@ def test_init_create_session(default_conf, mocker):
|
|||||||
# Check if init create a session
|
# Check if init create a session
|
||||||
init(default_conf)
|
init(default_conf)
|
||||||
assert hasattr(Trade, 'session')
|
assert hasattr(Trade, 'session')
|
||||||
assert type(Trade.session).__name__ is 'Session'
|
assert 'Session' in type(Trade.session).__name__
|
||||||
|
|
||||||
|
|
||||||
def test_init_dry_run_db(default_conf, mocker):
|
def test_init_dry_run_db(default_conf, mocker):
|
||||||
|
Loading…
Reference in New Issue
Block a user