Add a Constants class that contains Bot constants
This commit is contained in:
parent
585c2e31c6
commit
314ab0a84f
121
freqtrade/constants.py
Normal file
121
freqtrade/constants.py
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
# pragma pylint: disable=too-few-public-methods
|
||||||
|
|
||||||
|
"""
|
||||||
|
List bot constants
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
class Constants(object):
|
||||||
|
"""
|
||||||
|
Static class that contain all bot constants
|
||||||
|
"""
|
||||||
|
DYNAMIC_WHITELIST = 20 # pairs
|
||||||
|
PROCESS_THROTTLE_SECS = 5 # sec
|
||||||
|
TICKER_INTERVAL = 5 # min
|
||||||
|
HYPEROPT_EPOCH = 100 # epochs
|
||||||
|
RETRY_TIMEOUT = 30 # sec
|
||||||
|
|
||||||
|
# Required json-schema for user specified config
|
||||||
|
CONF_SCHEMA = {
|
||||||
|
'type': 'object',
|
||||||
|
'properties': {
|
||||||
|
'max_open_trades': {'type': 'integer', 'minimum': 1},
|
||||||
|
'ticker_interval': {'type': 'integer', 'enum': [1, 5, 30, 60, 1440]},
|
||||||
|
'stake_currency': {'type': 'string', 'enum': ['BTC', 'ETH', 'USDT']},
|
||||||
|
'stake_amount': {'type': 'number', 'minimum': 0.0005},
|
||||||
|
'fiat_display_currency': {'type': 'string', 'enum': ['AUD', 'BRL', 'CAD', 'CHF',
|
||||||
|
'CLP', 'CNY', 'CZK', 'DKK',
|
||||||
|
'EUR', 'GBP', 'HKD', 'HUF',
|
||||||
|
'IDR', 'ILS', 'INR', 'JPY',
|
||||||
|
'KRW', 'MXN', 'MYR', 'NOK',
|
||||||
|
'NZD', 'PHP', 'PKR', 'PLN',
|
||||||
|
'RUB', 'SEK', 'SGD', 'THB',
|
||||||
|
'TRY', 'TWD', 'ZAR', 'USD']},
|
||||||
|
'dry_run': {'type': 'boolean'},
|
||||||
|
'minimal_roi': {
|
||||||
|
'type': 'object',
|
||||||
|
'patternProperties': {
|
||||||
|
'^[0-9.]+$': {'type': 'number'}
|
||||||
|
},
|
||||||
|
'minProperties': 1
|
||||||
|
},
|
||||||
|
'stoploss': {'type': 'number', 'maximum': 0, 'exclusiveMaximum': True},
|
||||||
|
'unfilledtimeout': {'type': 'integer', 'minimum': 0},
|
||||||
|
'bid_strategy': {
|
||||||
|
'type': 'object',
|
||||||
|
'properties': {
|
||||||
|
'ask_last_balance': {
|
||||||
|
'type': 'number',
|
||||||
|
'minimum': 0,
|
||||||
|
'maximum': 1,
|
||||||
|
'exclusiveMaximum': False
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'required': ['ask_last_balance']
|
||||||
|
},
|
||||||
|
'exchange': {'$ref': '#/definitions/exchange'},
|
||||||
|
'experimental': {
|
||||||
|
'type': 'object',
|
||||||
|
'properties': {
|
||||||
|
'use_sell_signal': {'type': 'boolean'},
|
||||||
|
'sell_profit_only': {'type': 'boolean'}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'telegram': {
|
||||||
|
'type': 'object',
|
||||||
|
'properties': {
|
||||||
|
'enabled': {'type': 'boolean'},
|
||||||
|
'token': {'type': 'string'},
|
||||||
|
'chat_id': {'type': 'string'},
|
||||||
|
},
|
||||||
|
'required': ['enabled', 'token', 'chat_id']
|
||||||
|
},
|
||||||
|
'initial_state': {'type': 'string', 'enum': ['running', 'stopped']},
|
||||||
|
'internals': {
|
||||||
|
'type': 'object',
|
||||||
|
'properties': {
|
||||||
|
'process_throttle_secs': {'type': 'number'},
|
||||||
|
'interval': {'type': 'integer'}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'definitions': {
|
||||||
|
'exchange': {
|
||||||
|
'type': 'object',
|
||||||
|
'properties': {
|
||||||
|
'name': {'type': 'string'},
|
||||||
|
'key': {'type': 'string'},
|
||||||
|
'secret': {'type': 'string'},
|
||||||
|
'pair_whitelist': {
|
||||||
|
'type': 'array',
|
||||||
|
'items': {
|
||||||
|
'type': 'string',
|
||||||
|
'pattern': '^[0-9A-Z]+_[0-9A-Z]+$'
|
||||||
|
},
|
||||||
|
'uniqueItems': True
|
||||||
|
},
|
||||||
|
'pair_blacklist': {
|
||||||
|
'type': 'array',
|
||||||
|
'items': {
|
||||||
|
'type': 'string',
|
||||||
|
'pattern': '^[0-9A-Z]+_[0-9A-Z]+$'
|
||||||
|
},
|
||||||
|
'uniqueItems': True
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'required': ['name', 'key', 'secret', 'pair_whitelist']
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'anyOf': [
|
||||||
|
{'required': ['exchange']}
|
||||||
|
],
|
||||||
|
'required': [
|
||||||
|
'max_open_trades',
|
||||||
|
'stake_currency',
|
||||||
|
'stake_amount',
|
||||||
|
'fiat_display_currency',
|
||||||
|
'dry_run',
|
||||||
|
'bid_strategy',
|
||||||
|
'telegram'
|
||||||
|
]
|
||||||
|
}
|
281
freqtrade/tests/conftest_old.py
Normal file
281
freqtrade/tests/conftest_old.py
Normal file
@ -0,0 +1,281 @@
|
|||||||
|
# pragma pylint: disable=missing-docstring
|
||||||
|
from datetime import datetime
|
||||||
|
from unittest.mock import MagicMock
|
||||||
|
from functools import reduce
|
||||||
|
|
||||||
|
import json
|
||||||
|
import arrow
|
||||||
|
import pytest
|
||||||
|
from jsonschema import validate
|
||||||
|
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
|
||||||
|
|
||||||
|
|
||||||
|
def log_has(line, logs):
|
||||||
|
# caplog mocker returns log as a tuple: ('freqtrade.analyze', logging.WARNING, 'foobar')
|
||||||
|
# and we want to match line against foobar in the tuple
|
||||||
|
return reduce(lambda a, b: a or b,
|
||||||
|
filter(lambda x: x[2] == line, logs),
|
||||||
|
False)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(scope="module")
|
||||||
|
def default_conf():
|
||||||
|
""" Returns validated configuration suitable for most tests """
|
||||||
|
configuration = {
|
||||||
|
"max_open_trades": 1,
|
||||||
|
"stake_currency": "BTC",
|
||||||
|
"stake_amount": 0.001,
|
||||||
|
"fiat_display_currency": "USD",
|
||||||
|
"ticker_interval": 5,
|
||||||
|
"dry_run": True,
|
||||||
|
"minimal_roi": {
|
||||||
|
"40": 0.0,
|
||||||
|
"30": 0.01,
|
||||||
|
"20": 0.02,
|
||||||
|
"0": 0.04
|
||||||
|
},
|
||||||
|
"stoploss": -0.10,
|
||||||
|
"unfilledtimeout": 600,
|
||||||
|
"bid_strategy": {
|
||||||
|
"ask_last_balance": 0.0
|
||||||
|
},
|
||||||
|
"exchange": {
|
||||||
|
"name": "bittrex",
|
||||||
|
"enabled": True,
|
||||||
|
"key": "key",
|
||||||
|
"secret": "secret",
|
||||||
|
"pair_whitelist": [
|
||||||
|
"BTC_ETH",
|
||||||
|
"BTC_TKN",
|
||||||
|
"BTC_TRST",
|
||||||
|
"BTC_SWT",
|
||||||
|
"BTC_BCC"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"telegram": {
|
||||||
|
"enabled": True,
|
||||||
|
"token": "token",
|
||||||
|
"chat_id": "0"
|
||||||
|
},
|
||||||
|
"initial_state": "running"
|
||||||
|
}
|
||||||
|
validate(configuration, CONF_SCHEMA)
|
||||||
|
return configuration
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def update():
|
||||||
|
_update = Update(0)
|
||||||
|
_update.message = Message(0, 0, datetime.utcnow(), Chat(0, 0))
|
||||||
|
return _update
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def ticker():
|
||||||
|
return MagicMock(return_value={
|
||||||
|
'bid': 0.00001098,
|
||||||
|
'ask': 0.00001099,
|
||||||
|
'last': 0.00001098,
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def ticker_sell_up():
|
||||||
|
return MagicMock(return_value={
|
||||||
|
'bid': 0.00001172,
|
||||||
|
'ask': 0.00001173,
|
||||||
|
'last': 0.00001172,
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def ticker_sell_down():
|
||||||
|
return MagicMock(return_value={
|
||||||
|
'bid': 0.00001044,
|
||||||
|
'ask': 0.00001043,
|
||||||
|
'last': 0.00001044,
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def health():
|
||||||
|
return MagicMock(return_value=[{
|
||||||
|
'Currency': 'BTC',
|
||||||
|
'IsActive': True,
|
||||||
|
'LastChecked': '2017-11-13T20:15:00.00',
|
||||||
|
'Notice': None
|
||||||
|
}, {
|
||||||
|
'Currency': 'ETH',
|
||||||
|
'IsActive': True,
|
||||||
|
'LastChecked': '2017-11-13T20:15:00.00',
|
||||||
|
'Notice': None
|
||||||
|
}, {
|
||||||
|
'Currency': 'TRST',
|
||||||
|
'IsActive': True,
|
||||||
|
'LastChecked': '2017-11-13T20:15:00.00',
|
||||||
|
'Notice': None
|
||||||
|
}, {
|
||||||
|
'Currency': 'SWT',
|
||||||
|
'IsActive': True,
|
||||||
|
'LastChecked': '2017-11-13T20:15:00.00',
|
||||||
|
'Notice': None
|
||||||
|
}, {
|
||||||
|
'Currency': 'BCC',
|
||||||
|
'IsActive': False,
|
||||||
|
'LastChecked': '2017-11-13T20:15:00.00',
|
||||||
|
'Notice': None
|
||||||
|
}])
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def limit_buy_order():
|
||||||
|
return {
|
||||||
|
'id': 'mocked_limit_buy',
|
||||||
|
'type': 'LIMIT_BUY',
|
||||||
|
'pair': 'mocked',
|
||||||
|
'opened': str(arrow.utcnow().datetime),
|
||||||
|
'rate': 0.00001099,
|
||||||
|
'amount': 90.99181073,
|
||||||
|
'remaining': 0.0,
|
||||||
|
'closed': str(arrow.utcnow().datetime),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def limit_buy_order_old():
|
||||||
|
return {
|
||||||
|
'id': 'mocked_limit_buy_old',
|
||||||
|
'type': 'LIMIT_BUY',
|
||||||
|
'pair': 'BTC_ETH',
|
||||||
|
'opened': str(arrow.utcnow().shift(minutes=-601).datetime),
|
||||||
|
'rate': 0.00001099,
|
||||||
|
'amount': 90.99181073,
|
||||||
|
'remaining': 90.99181073,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def limit_sell_order_old():
|
||||||
|
return {
|
||||||
|
'id': 'mocked_limit_sell_old',
|
||||||
|
'type': 'LIMIT_SELL',
|
||||||
|
'pair': 'BTC_ETH',
|
||||||
|
'opened': str(arrow.utcnow().shift(minutes=-601).datetime),
|
||||||
|
'rate': 0.00001099,
|
||||||
|
'amount': 90.99181073,
|
||||||
|
'remaining': 90.99181073,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def limit_buy_order_old_partial():
|
||||||
|
return {
|
||||||
|
'id': 'mocked_limit_buy_old_partial',
|
||||||
|
'type': 'LIMIT_BUY',
|
||||||
|
'pair': 'BTC_ETH',
|
||||||
|
'opened': str(arrow.utcnow().shift(minutes=-601).datetime),
|
||||||
|
'rate': 0.00001099,
|
||||||
|
'amount': 90.99181073,
|
||||||
|
'remaining': 67.99181073,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def limit_sell_order():
|
||||||
|
return {
|
||||||
|
'id': 'mocked_limit_sell',
|
||||||
|
'type': 'LIMIT_SELL',
|
||||||
|
'pair': 'mocked',
|
||||||
|
'opened': str(arrow.utcnow().datetime),
|
||||||
|
'rate': 0.00001173,
|
||||||
|
'amount': 90.99181073,
|
||||||
|
'remaining': 0.0,
|
||||||
|
'closed': str(arrow.utcnow().datetime),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def ticker_history():
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
"O": 8.794e-05,
|
||||||
|
"H": 8.948e-05,
|
||||||
|
"L": 8.794e-05,
|
||||||
|
"C": 8.88e-05,
|
||||||
|
"V": 991.09056638,
|
||||||
|
"T": "2017-11-26T08:50:00",
|
||||||
|
"BV": 0.0877869
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"O": 8.88e-05,
|
||||||
|
"H": 8.942e-05,
|
||||||
|
"L": 8.88e-05,
|
||||||
|
"C": 8.893e-05,
|
||||||
|
"V": 658.77935965,
|
||||||
|
"T": "2017-11-26T08:55:00",
|
||||||
|
"BV": 0.05874751
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"O": 8.891e-05,
|
||||||
|
"H": 8.893e-05,
|
||||||
|
"L": 8.875e-05,
|
||||||
|
"C": 8.877e-05,
|
||||||
|
"V": 7920.73570705,
|
||||||
|
"T": "2017-11-26T09:00:00",
|
||||||
|
"BV": 0.7039405
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def ticker_history_without_bv():
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
"O": 8.794e-05,
|
||||||
|
"H": 8.948e-05,
|
||||||
|
"L": 8.794e-05,
|
||||||
|
"C": 8.88e-05,
|
||||||
|
"V": 991.09056638,
|
||||||
|
"T": "2017-11-26T08:50:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"O": 8.88e-05,
|
||||||
|
"H": 8.942e-05,
|
||||||
|
"L": 8.88e-05,
|
||||||
|
"C": 8.893e-05,
|
||||||
|
"V": 658.77935965,
|
||||||
|
"T": "2017-11-26T08:55:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"O": 8.891e-05,
|
||||||
|
"H": 8.893e-05,
|
||||||
|
"L": 8.875e-05,
|
||||||
|
"C": 8.877e-05,
|
||||||
|
"V": 7920.73570705,
|
||||||
|
"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
|
||||||
|
|
||||||
|
|
||||||
|
# FIX:
|
||||||
|
# Create an fixture/function
|
||||||
|
# that inserts a trade of some type and open-status
|
||||||
|
# return the open-order-id
|
||||||
|
# See tests in rpc/main that could use this
|
28
freqtrade/tests/test_constants.py
Normal file
28
freqtrade/tests/test_constants.py
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
"""
|
||||||
|
Unit test file for constants.py
|
||||||
|
"""
|
||||||
|
|
||||||
|
from freqtrade.constants import Constants
|
||||||
|
|
||||||
|
|
||||||
|
def test_constant_object() -> None:
|
||||||
|
"""
|
||||||
|
Test the Constants object has the mandatory Constants
|
||||||
|
:return: None
|
||||||
|
"""
|
||||||
|
constant = Constants()
|
||||||
|
assert hasattr(constant, 'CONF_SCHEMA')
|
||||||
|
assert hasattr(constant, 'DYNAMIC_WHITELIST')
|
||||||
|
assert hasattr(constant, 'PROCESS_THROTTLE_SECS')
|
||||||
|
assert hasattr(constant, 'TICKER_INTERVAL')
|
||||||
|
assert hasattr(constant, 'HYPEROPT_EPOCH')
|
||||||
|
assert hasattr(constant, 'RETRY_TIMEOUT')
|
||||||
|
|
||||||
|
|
||||||
|
def test_conf_schema() -> None:
|
||||||
|
"""
|
||||||
|
Test the CONF_SCHEMA is from the right type
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
constant = Constants()
|
||||||
|
assert isinstance(constant.CONF_SCHEMA, dict)
|
Loading…
Reference in New Issue
Block a user