Merge branch 'develop' into fix_dry_run_stop_price

This commit is contained in:
misagh 2018-11-30 10:37:58 +01:00
commit 8ff82e3dac
19 changed files with 277 additions and 160 deletions

View File

@ -1,9 +1,15 @@
sudo: true sudo: true
os: os:
- linux - linux
dist: trusty
language: python language: python
python: python:
- 3.6 - 3.6
services:
- docker
env:
global:
- IMAGE_NAME=freqtradeorg/freqtrade
addons: addons:
apt: apt:
packages: packages:
@ -11,24 +17,38 @@ addons:
- libdw-dev - libdw-dev
- binutils-dev - binutils-dev
install: install:
- ./install_ta-lib.sh - ./build_helpers/install_ta-lib.sh
- export LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH - export LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH
- pip install --upgrade flake8 coveralls pytest-random-order pytest-asyncio mypy - pip install --upgrade flake8 coveralls pytest-random-order pytest-asyncio mypy
- pip install -r requirements.txt - pip install -r requirements.txt
- pip install -e . - pip install -e .
jobs: jobs:
include: include:
- script: - stage: tests
script:
- pytest --cov=freqtrade --cov-config=.coveragerc freqtrade/tests/ - pytest --cov=freqtrade --cov-config=.coveragerc freqtrade/tests/
- coveralls - coveralls
name: pytest
- script: - script:
- cp config.json.example config.json - cp config.json.example config.json
- python freqtrade/main.py --datadir freqtrade/tests/testdata backtesting - python freqtrade/main.py --datadir freqtrade/tests/testdata backtesting
name: backtest
- script: - script:
- cp config.json.example config.json - cp config.json.example config.json
- python freqtrade/main.py --datadir freqtrade/tests/testdata hyperopt -e 5 - python freqtrade/main.py --datadir freqtrade/tests/testdata hyperopt -e 5
name: hyperopt
- script: flake8 freqtrade - script: flake8 freqtrade
name: flake8
- script: mypy freqtrade - script: mypy freqtrade
name: mypy
- stage: docker
if: branch in (master, develop, feat/improve_travis) AND (type in (push, cron))
script:
- build_helpers/publish_docker.sh
name: "Build and test and push docker image"
notifications: notifications:
slack: slack:
secure: bKLXmOrx8e2aPZl7W8DA5BdPAXWGpI5UzST33oc1G/thegXcDVmHBTJrBs4sZak6bgAclQQrdZIsRd2eFYzHLalJEaw6pk7hoAw8SvLnZO0ZurWboz7qg2+aZZXfK4eKl/VUe4sM9M4e/qxjkK+yWG7Marg69c4v1ypF7ezUi1fPYILYw8u0paaiX0N5UX8XNlXy+PBlga2MxDjUY70MuajSZhPsY2pDUvYnMY1D/7XN3cFW0g+3O8zXjF0IF4q1Z/1ASQe+eYjKwPQacE+O8KDD+ZJYoTOFBAPllrtpO1jnOPFjNGf3JIbVMZw4bFjIL0mSQaiSUaUErbU3sFZ5Or79rF93XZ81V7uEZ55vD8KMfR2CB1cQJcZcj0v50BxLo0InkFqa0Y8Nra3sbpV4fV5Oe8pDmomPJrNFJnX6ULQhQ1gTCe0M5beKgVms5SITEpt4/Y0CmLUr6iHDT0CUiyMIRWAXdIgbGh1jfaWOMksybeRevlgDsIsNBjXmYI1Sw2ZZR2Eo2u4R6zyfyjOMLwYJ3vgq9IrACv2w5nmf0+oguMWHf6iWi2hiOqhlAN1W74+3HsYQcqnuM3LGOmuCnPprV1oGBqkPXjIFGpy21gNx4vHfO1noLUyJnMnlu2L7SSuN1CdLsnjJ1hVjpJjPfqB4nn8g12x87TqM1bOm+3Q= secure: bKLXmOrx8e2aPZl7W8DA5BdPAXWGpI5UzST33oc1G/thegXcDVmHBTJrBs4sZak6bgAclQQrdZIsRd2eFYzHLalJEaw6pk7hoAw8SvLnZO0ZurWboz7qg2+aZZXfK4eKl/VUe4sM9M4e/qxjkK+yWG7Marg69c4v1ypF7ezUi1fPYILYw8u0paaiX0N5UX8XNlXy+PBlga2MxDjUY70MuajSZhPsY2pDUvYnMY1D/7XN3cFW0g+3O8zXjF0IF4q1Z/1ASQe+eYjKwPQacE+O8KDD+ZJYoTOFBAPllrtpO1jnOPFjNGf3JIbVMZw4bFjIL0mSQaiSUaUErbU3sFZ5Or79rF93XZ81V7uEZ55vD8KMfR2CB1cQJcZcj0v50BxLo0InkFqa0Y8Nra3sbpV4fV5Oe8pDmomPJrNFJnX6ULQhQ1gTCe0M5beKgVms5SITEpt4/Y0CmLUr6iHDT0CUiyMIRWAXdIgbGh1jfaWOMksybeRevlgDsIsNBjXmYI1Sw2ZZR2Eo2u4R6zyfyjOMLwYJ3vgq9IrACv2w5nmf0+oguMWHf6iWi2hiOqhlAN1W74+3HsYQcqnuM3LGOmuCnPprV1oGBqkPXjIFGpy21gNx4vHfO1noLUyJnMnlu2L7SSuN1CdLsnjJ1hVjpJjPfqB4nn8g12x87TqM1bOm+3Q=

View File

@ -1,19 +1,20 @@
FROM python:3.7.0-slim-stretch FROM python:3.7.0-slim-stretch
# Install TA-lib RUN apt-get update \
RUN apt-get update && apt-get -y install curl build-essential && apt-get clean && apt-get -y install curl build-essential \
RUN curl -L http://prdownloads.sourceforge.net/ta-lib/ta-lib-0.4.0-src.tar.gz | \ && apt-get clean \
tar xzvf - && \ && pip install --upgrade pip
cd ta-lib && \
sed -i "s|0.00000001|0.000000000000000001 |g" src/ta_func/ta_utility.h && \
./configure && make && make install && \
cd .. && rm -rf ta-lib
ENV LD_LIBRARY_PATH /usr/local/lib
# Prepare environment # Prepare environment
RUN mkdir /freqtrade RUN mkdir /freqtrade
WORKDIR /freqtrade WORKDIR /freqtrade
# Install TA-lib
COPY build_helpers/* /tmp/
RUN cd /tmp && /tmp/install_ta-lib.sh && rm -r /tmp/*ta-lib*
ENV LD_LIBRARY_PATH /usr/local/lib
# Install dependencies # Install dependencies
COPY requirements.txt /freqtrade/ COPY requirements.txt /freqtrade/
RUN pip install numpy --no-cache-dir \ RUN pip install numpy --no-cache-dir \

6
Dockerfile.technical Normal file
View File

@ -0,0 +1,6 @@
FROM freqtradeorg/freqtrade:develop
RUN apt-get update \
&& apt-get -y install git \
&& apt-get clean \
&& pip install git+https://github.com/berlinguyinca/technical

13
build_helpers/install_ta-lib.sh Executable file
View File

@ -0,0 +1,13 @@
if [ ! -f "ta-lib/CHANGELOG.TXT" ]; then
tar zxvf ta-lib-0.4.0-src.tar.gz
cd ta-lib \
&& sed -i.bak "s|0.00000001|0.000000000000000001 |g" src/ta_func/ta_utility.h \
&& ./configure \
&& make \
&& which sudo && sudo make install || make install \
&& cd ..
else
echo "TA-lib already installed, skipping download and build."
cd ta-lib && sudo make install && cd ..
fi

57
build_helpers/publish_docker.sh Executable file
View File

@ -0,0 +1,57 @@
#!/bin/sh
# - export TAG=`if [ "$TRAVIS_BRANCH" == "develop" ]; then echo "latest"; else echo $TRAVIS_BRANCH ; fi`
# Replace / with _ to create a valid tag
TAG=$(echo "${TRAVIS_BRANCH}" | sed -e "s/\//_/")
if [ "${TRAVIS_EVENT_TYPE}" = "cron" ]; then
echo "event ${TRAVIS_EVENT_TYPE}: full rebuild - skipping cache"
docker build -t freqtrade:${TAG} .
else
echo "event ${TRAVIS_EVENT_TYPE}: building with cache"
# Pull last build to avoid rebuilding the whole image
docker pull ${REPO}:${TAG}
docker build --cache-from ${IMAGE_NAME}:${TAG} -t freqtrade:${TAG} .
fi
if [ $? -ne 0 ]; then
echo "failed building image"
return 1
fi
# Run backtest
docker run --rm -it -v $(pwd)/config.json.example:/freqtrade/config.json:ro freqtrade:${TAG} --datadir freqtrade/tests/testdata backtesting
if [ $? -ne 0 ]; then
echo "failed running backtest"
return 1
fi
# Tag image for upload
docker tag freqtrade:$TAG ${IMAGE_NAME}:$TAG
if [ $? -ne 0 ]; then
echo "failed tagging image"
return 1
fi
# Tag as latest for develop builds
if [ "${TRAVIS_BRANCH}" = "develop" ]; then
docker tag freqtrade:$TAG ${IMAGE_NAME}:latest
fi
# Login
echo "$DOCKER_PASS" | docker login -u $DOCKER_USER --password-stdin
if [ $? -ne 0 ]; then
echo "failed login"
return 1
fi
# Show all available images
docker images
docker push ${IMAGE_NAME}
if [ $? -ne 0 ]; then
echo "failed pushing repo"
return 1
fi

View File

@ -0,0 +1,83 @@
{
"max_open_trades": 3,
"stake_currency": "BTC",
"stake_amount": 0.05,
"fiat_display_currency": "USD",
"ticker_interval" : "5m",
"dry_run": true,
"trailing_stop": false,
"unfilledtimeout": {
"buy": 10,
"sell": 30
},
"bid_strategy": {
"ask_last_balance": 0.0,
"use_order_book": false,
"order_book_top": 1,
"check_depth_of_market": {
"enabled": false,
"bids_to_ask_delta": 1
}
},
"ask_strategy":{
"use_order_book": false,
"order_book_min": 1,
"order_book_max": 9
},
"exchange": {
"name": "binance",
"key": "your_exchange_key",
"secret": "your_exchange_secret",
"ccxt_config": {"enableRateLimit": true},
"ccxt_async_config": {
"enableRateLimit": false
},
"pair_whitelist": [
"AST/BTC",
"ETC/BTC",
"ETH/BTC",
"EOS/BTC",
"IOTA/BTC",
"LTC/BTC",
"MTH/BTC",
"NCASH/BTC",
"TNT/BTC",
"XMR/BTC",
"XLM/BTC",
"XRP/BTC"
],
"pair_blacklist": [
"BNB/BTC"
]
},
"experimental": {
"use_sell_signal": false,
"sell_profit_only": false,
"ignore_roi_if_buy_signal": false
},
"edge": {
"enabled": false,
"process_throttle_secs": 3600,
"calculate_since_number_of_days": 7,
"total_capital_in_stake_currency": 0.5,
"allowed_risk": 0.01,
"stoploss_range_min": -0.01,
"stoploss_range_max": -0.1,
"stoploss_range_step": -0.01,
"minimum_winrate": 0.60,
"minimum_expectancy": 0.20,
"min_trade_number": 10,
"max_trade_duration_minute": 1440,
"remove_pumps": false
},
"telegram": {
"enabled": false,
"token": "your_telegram_token",
"chat_id": "your_telegram_chat_id"
},
"initial_state": "running",
"forcebuy_enable": false,
"internals": {
"process_throttle_secs": 5
}
}

View File

@ -109,7 +109,25 @@ Dry-Run
touch tradesv3.dryrun.sqlite touch tradesv3.dryrun.sqlite
``` ```
### 2. Build the Docker image ### 2. Download or build the docker image
Either use the prebuilt image from docker hub - or build the image yourself if you would like more control on which version is used.
Branches / tags available can be checked out on [Dockerhub](https://hub.docker.com/r/freqtradeorg/freqtrade/tags/).
#### 2.1. Download the docker image
Pull the image from docker hub and (optionally) change the name of the image
```bash
docker pull freqtradeorg/freqtrade:develop
# Optionally tag the repository so the run-commands remain shorter
docker tag freqtradeorg/freqtrade:develop freqtrade
```
To update the image, simply run the above commands again and restart your running container.
#### 2.2. Build the Docker image
```bash ```bash
cd freqtrade cd freqtrade

View File

@ -157,7 +157,12 @@ class Edge():
return position_size return position_size
def stoploss(self, pair: str) -> float: def stoploss(self, pair: str) -> float:
if pair in self._cached_pairs:
return self._cached_pairs[pair].stoploss return self._cached_pairs[pair].stoploss
else:
logger.warning('tried to access stoploss of a non-existing pair, '
'strategy stoploss is returned instead.')
return self.strategy.stoploss
def adjust(self, pairs) -> list: def adjust(self, pairs) -> list:
""" """

View File

@ -207,7 +207,8 @@ class Exchange(object):
f'Pair {pair} not compatible with stake_currency: {stake_cur}') f'Pair {pair} not compatible with stake_currency: {stake_cur}')
if self.markets and pair not in self.markets: if self.markets and pair not in self.markets:
raise OperationalException( raise OperationalException(
f'Pair {pair} is not available at {self.name}') f'Pair {pair} is not available at {self.name}'
f'Please remove {pair} from your whitelist.')
def validate_timeframes(self, timeframe: List[str]) -> None: def validate_timeframes(self, timeframe: List[str]) -> None:
""" """
@ -478,6 +479,8 @@ class Exchange(object):
# Because some exchange sort Tickers ASC and other DESC. # Because some exchange sort Tickers ASC and other DESC.
# Ex: Bittrex returns a list of tickers ASC (oldest first, newest last) # Ex: Bittrex returns a list of tickers ASC (oldest first, newest last)
# when GDAX returns a list of tickers DESC (newest first, oldest last) # when GDAX returns a list of tickers DESC (newest first, oldest last)
# Only sort if necessary to save computing time
if data and data[0][0] > data[-1][0]:
data = sorted(data, key=lambda x: x[0]) data = sorted(data, key=lambda x: x[0])
# keeping last candle time as last refreshed time of the pair # keeping last candle time as last refreshed time of the pair
@ -500,51 +503,6 @@ class Exchange(object):
except ccxt.BaseError as e: except ccxt.BaseError as e:
raise OperationalException(f'Could not fetch ticker data. Msg: {e}') raise OperationalException(f'Could not fetch ticker data. Msg: {e}')
@retrier
def get_candle_history(self, pair: str, tick_interval: str,
since_ms: Optional[int] = None) -> List[Dict]:
try:
# last item should be in the time interval [now - tick_interval, now]
till_time_ms = arrow.utcnow().shift(
minutes=-constants.TICKER_INTERVAL_MINUTES[tick_interval]
).timestamp * 1000
# it looks as if some exchanges return cached data
# and they update it one in several minute, so 10 mins interval
# is necessary to skeep downloading of an empty array when all
# chached data was already downloaded
till_time_ms = min(till_time_ms, arrow.utcnow().shift(minutes=-10).timestamp * 1000)
data: List[Dict[Any, Any]] = []
while not since_ms or since_ms < till_time_ms:
data_part = self._api.fetch_ohlcv(pair, timeframe=tick_interval, since=since_ms)
# Because some exchange sort Tickers ASC and other DESC.
# Ex: Bittrex returns a list of tickers ASC (oldest first, newest last)
# when GDAX returns a list of tickers DESC (newest first, oldest last)
data_part = sorted(data_part, key=lambda x: x[0])
if not data_part:
break
logger.debug('Downloaded data for %s time range [%s, %s]',
pair,
arrow.get(data_part[0][0] / 1000).format(),
arrow.get(data_part[-1][0] / 1000).format())
data.extend(data_part)
since_ms = data[-1][0] + 1
return data
except ccxt.NotSupported as e:
raise OperationalException(
f'Exchange {self._api.name} does not support fetching historical candlestick data.'
f'Message: {e}')
except (ccxt.NetworkError, ccxt.ExchangeError) as e:
raise TemporaryError(
f'Could not load ticker history due to {e.__class__.__name__}. Message: {e}')
except ccxt.BaseError as e:
raise OperationalException(f'Could not fetch ticker data. Msg: {e}')
@retrier @retrier
def cancel_order(self, order_id: str, pair: str) -> None: def cancel_order(self, order_id: str, pair: str) -> None:
if self._conf['dry_run']: if self._conf['dry_run']:

View File

@ -11,7 +11,7 @@ logger = logging.getLogger(__name__)
def parse_ticker_dataframe(ticker: list) -> DataFrame: def parse_ticker_dataframe(ticker: list) -> DataFrame:
""" """
Analyses the trend for the given ticker history Analyses the trend for the given ticker history
:param ticker: See exchange.get_candle_history :param ticker: ticker list, as returned by exchange.async_get_candle_history
:return: DataFrame :return: DataFrame
""" """
cols = ['date', 'open', 'high', 'low', 'close', 'volume'] cols = ['date', 'open', 'high', 'low', 'close', 'volume']

View File

@ -4,7 +4,6 @@ import logging
from datetime import datetime from datetime import datetime
from functools import reduce from functools import reduce
from typing import Dict, Optional from typing import Dict, Optional
from collections import namedtuple
from unittest.mock import MagicMock, PropertyMock from unittest.mock import MagicMock, PropertyMock
import arrow import arrow
@ -13,7 +12,7 @@ from telegram import Chat, Message, Update
from freqtrade.exchange.exchange_helpers import parse_ticker_dataframe from freqtrade.exchange.exchange_helpers import parse_ticker_dataframe
from freqtrade.exchange import Exchange from freqtrade.exchange import Exchange
from freqtrade.edge import Edge from freqtrade.edge import Edge, PairInfo
from freqtrade.freqtradebot import FreqtradeBot from freqtrade.freqtradebot import FreqtradeBot
logging.getLogger('').setLevel(logging.INFO) logging.getLogger('').setLevel(logging.INFO)
@ -56,13 +55,11 @@ def patch_edge(mocker) -> None:
# "LTC/BTC", # "LTC/BTC",
# "XRP/BTC", # "XRP/BTC",
# "NEO/BTC" # "NEO/BTC"
pair_info = namedtuple(
'pair_info',
'stoploss, winrate, risk_reward_ratio, required_risk_reward, expectancy')
mocker.patch('freqtrade.edge.Edge._cached_pairs', mocker.PropertyMock( mocker.patch('freqtrade.edge.Edge._cached_pairs', mocker.PropertyMock(
return_value={ return_value={
'NEO/BTC': pair_info(-0.20, 0.66, 3.71, 0.50, 1.71), 'NEO/BTC': PairInfo(-0.20, 0.66, 3.71, 0.50, 1.71, 10, 25),
'LTC/BTC': pair_info(-0.21, 0.66, 3.71, 0.50, 1.71), 'LTC/BTC': PairInfo(-0.21, 0.66, 3.71, 0.50, 1.71, 11, 20),
} }
)) ))
mocker.patch('freqtrade.edge.Edge.stoploss', MagicMock(return_value=-0.20)) mocker.patch('freqtrade.edge.Edge.stoploss', MagicMock(return_value=-0.20))

View File

@ -152,6 +152,18 @@ def test_stoploss(mocker, default_conf):
assert edge.stoploss('E/F') == -0.01 assert edge.stoploss('E/F') == -0.01
def test_nonexisting_stoploss(mocker, default_conf):
freqtrade = get_patched_freqtradebot(mocker, default_conf)
edge = Edge(default_conf, freqtrade.exchange, freqtrade.strategy)
mocker.patch('freqtrade.edge.Edge._cached_pairs', mocker.PropertyMock(
return_value={
'E/F': PairInfo(-0.01, 0.66, 3.71, 0.50, 1.71, 10, 60),
}
))
assert edge.stoploss('N/O') == -0.1
def _validate_ohlc(buy_ohlc_sell_matrice): def _validate_ohlc(buy_ohlc_sell_matrice):
for index, ohlc in enumerate(buy_ohlc_sell_matrice): for index, ohlc in enumerate(buy_ohlc_sell_matrice):
# if not high < open < low or not high < close < low # if not high < open < low or not high < close < low

View File

@ -875,65 +875,10 @@ def make_fetch_ohlcv_mock(data):
return fetch_ohlcv_mock return fetch_ohlcv_mock
def test_get_candle_history(default_conf, mocker): @pytest.mark.asyncio
api_mock = MagicMock() async def test___async_get_candle_history_sort(default_conf, mocker):
tick = [ def sort_data(data, key):
[ return sorted(data, key=key)
1511686200000, # unix timestamp ms
1, # open
2, # high
3, # low
4, # close
5, # volume (in quote currency)
]
]
type(api_mock).has = PropertyMock(return_value={'fetchOHLCV': True})
api_mock.fetch_ohlcv = MagicMock(side_effect=make_fetch_ohlcv_mock(tick))
exchange = get_patched_exchange(mocker, default_conf, api_mock)
# retrieve original ticker
ticks = exchange.get_candle_history('ETH/BTC', default_conf['ticker_interval'])
assert ticks[0][0] == 1511686200000
assert ticks[0][1] == 1
assert ticks[0][2] == 2
assert ticks[0][3] == 3
assert ticks[0][4] == 4
assert ticks[0][5] == 5
# change ticker and ensure tick changes
new_tick = [
[
1511686210000, # unix timestamp ms
6, # open
7, # high
8, # low
9, # close
10, # volume (in quote currency)
]
]
api_mock.fetch_ohlcv = MagicMock(side_effect=make_fetch_ohlcv_mock(new_tick))
exchange = get_patched_exchange(mocker, default_conf, api_mock)
ticks = exchange.get_candle_history('ETH/BTC', default_conf['ticker_interval'])
assert ticks[0][0] == 1511686210000
assert ticks[0][1] == 6
assert ticks[0][2] == 7
assert ticks[0][3] == 8
assert ticks[0][4] == 9
assert ticks[0][5] == 10
ccxt_exceptionhandlers(mocker, default_conf, api_mock,
"get_candle_history", "fetch_ohlcv",
pair='ABCD/BTC', tick_interval=default_conf['ticker_interval'])
with pytest.raises(OperationalException, match=r'Exchange .* does not support.*'):
api_mock.fetch_ohlcv = MagicMock(side_effect=ccxt.NotSupported)
exchange = get_patched_exchange(mocker, default_conf, api_mock)
exchange.get_candle_history(pair='ABCD/BTC', tick_interval=default_conf['ticker_interval'])
def test_get_candle_history_sort(default_conf, mocker):
api_mock = MagicMock()
# GDAX use-case (real data from GDAX) # GDAX use-case (real data from GDAX)
# This ticker history is ordered DESC (newest first, oldest last) # This ticker history is ordered DESC (newest first, oldest last)
@ -949,13 +894,15 @@ def test_get_candle_history_sort(default_conf, mocker):
[1527830700000, 0.07652, 0.07652, 0.07651, 0.07652, 10.04822687], [1527830700000, 0.07652, 0.07652, 0.07651, 0.07652, 10.04822687],
[1527830400000, 0.07649, 0.07651, 0.07649, 0.07651, 2.5734867] [1527830400000, 0.07649, 0.07651, 0.07649, 0.07651, 2.5734867]
] ]
type(api_mock).has = PropertyMock(return_value={'fetchOHLCV': True}) exchange = get_patched_exchange(mocker, default_conf)
api_mock.fetch_ohlcv = MagicMock(side_effect=make_fetch_ohlcv_mock(tick)) exchange._api_async.fetch_ohlcv = get_mock_coro(tick)
sort_mock = mocker.patch('freqtrade.exchange.sorted', MagicMock(side_effect=sort_data))
exchange = get_patched_exchange(mocker, default_conf, api_mock)
# Test the ticker history sort # Test the ticker history sort
ticks = exchange.get_candle_history('ETH/BTC', default_conf['ticker_interval']) res = await exchange._async_get_candle_history('ETH/BTC', default_conf['ticker_interval'])
assert res[0] == 'ETH/BTC'
ticks = res[1]
assert sort_mock.call_count == 1
assert ticks[0][0] == 1527830400000 assert ticks[0][0] == 1527830400000
assert ticks[0][1] == 0.07649 assert ticks[0][1] == 0.07649
assert ticks[0][2] == 0.07651 assert ticks[0][2] == 0.07651
@ -984,11 +931,15 @@ def test_get_candle_history_sort(default_conf, mocker):
[1527830100000, 0.076695, 0.07671, 0.07624171, 0.07671, 1.80689244], [1527830100000, 0.076695, 0.07671, 0.07624171, 0.07671, 1.80689244],
[1527830400000, 0.07671, 0.07674399, 0.07629216, 0.07655213, 2.31452783] [1527830400000, 0.07671, 0.07674399, 0.07629216, 0.07655213, 2.31452783]
] ]
type(api_mock).has = PropertyMock(return_value={'fetchOHLCV': True}) exchange._api_async.fetch_ohlcv = get_mock_coro(tick)
api_mock.fetch_ohlcv = MagicMock(side_effect=make_fetch_ohlcv_mock(tick)) # Reset sort mock
exchange = get_patched_exchange(mocker, default_conf, api_mock) sort_mock = mocker.patch('freqtrade.exchange.sorted', MagicMock(side_effect=sort_data))
# Test the ticker history sort # Test the ticker history sort
ticks = exchange.get_candle_history('ETH/BTC', default_conf['ticker_interval']) res = await exchange._async_get_candle_history('ETH/BTC', default_conf['ticker_interval'])
assert res[0] == 'ETH/BTC'
ticks = res[1]
# Sorted not called again - data is already in order
assert sort_mock.call_count == 0
assert ticks[0][0] == 1527827700000 assert ticks[0][0] == 1527827700000
assert ticks[0][1] == 0.07659999 assert ticks[0][1] == 0.07659999
assert ticks[0][2] == 0.0766 assert ticks[0][2] == 0.0766

View File

@ -292,7 +292,7 @@ def test_edge_overrides_stoploss(limit_buy_order, fee, markets, caplog, mocker,
freqtrade = FreqtradeBot(edge_conf) freqtrade = FreqtradeBot(edge_conf)
freqtrade.active_pair_whitelist = ['NEO/BTC'] freqtrade.active_pair_whitelist = ['NEO/BTC']
patch_get_signal(freqtrade) patch_get_signal(freqtrade)
freqtrade.strategy.min_roi_reached = lambda trade, current_profit, current_time: False freqtrade.strategy.min_roi_reached = MagicMock(return_value=False)
freqtrade.create_trade() freqtrade.create_trade()
trade = Trade.query.first() trade = Trade.query.first()
trade.update(limit_buy_order) trade.update(limit_buy_order)
@ -332,7 +332,7 @@ def test_edge_should_ignore_strategy_stoploss(limit_buy_order, fee, markets,
freqtrade = FreqtradeBot(edge_conf) freqtrade = FreqtradeBot(edge_conf)
freqtrade.active_pair_whitelist = ['NEO/BTC'] freqtrade.active_pair_whitelist = ['NEO/BTC']
patch_get_signal(freqtrade) patch_get_signal(freqtrade)
freqtrade.strategy.min_roi_reached = lambda trade, current_profit, current_time: False freqtrade.strategy.min_roi_reached = MagicMock(return_value=False)
freqtrade.create_trade() freqtrade.create_trade()
trade = Trade.query.first() trade = Trade.query.first()
trade.update(limit_buy_order) trade.update(limit_buy_order)
@ -1010,7 +1010,7 @@ def test_handle_overlpapping_signals(default_conf, ticker, limit_buy_order,
freqtrade = FreqtradeBot(default_conf) freqtrade = FreqtradeBot(default_conf)
patch_get_signal(freqtrade, value=(True, True)) patch_get_signal(freqtrade, value=(True, True))
freqtrade.strategy.min_roi_reached = lambda trade, current_profit, current_time: False freqtrade.strategy.min_roi_reached = MagicMock(return_value=False)
freqtrade.create_trade() freqtrade.create_trade()
@ -1066,7 +1066,7 @@ def test_handle_trade_roi(default_conf, ticker, limit_buy_order,
freqtrade = FreqtradeBot(default_conf) freqtrade = FreqtradeBot(default_conf)
patch_get_signal(freqtrade, value=(True, False)) patch_get_signal(freqtrade, value=(True, False))
freqtrade.strategy.min_roi_reached = lambda trade, current_profit, current_time: True freqtrade.strategy.min_roi_reached = MagicMock(return_value=True)
freqtrade.create_trade() freqtrade.create_trade()
@ -1099,7 +1099,7 @@ def test_handle_trade_experimental(
freqtrade = FreqtradeBot(default_conf) freqtrade = FreqtradeBot(default_conf)
patch_get_signal(freqtrade) patch_get_signal(freqtrade)
freqtrade.strategy.min_roi_reached = lambda trade, current_profit, current_time: False freqtrade.strategy.min_roi_reached = MagicMock(return_value=False)
freqtrade.create_trade() freqtrade.create_trade()
trade = Trade.query.first() trade = Trade.query.first()
@ -1633,7 +1633,7 @@ def test_sell_profit_only_enable_profit(default_conf, limit_buy_order,
} }
freqtrade = FreqtradeBot(default_conf) freqtrade = FreqtradeBot(default_conf)
patch_get_signal(freqtrade) patch_get_signal(freqtrade)
freqtrade.strategy.min_roi_reached = lambda trade, current_profit, current_time: False freqtrade.strategy.min_roi_reached = MagicMock(return_value=False)
freqtrade.create_trade() freqtrade.create_trade()
@ -1665,7 +1665,7 @@ def test_sell_profit_only_disable_profit(default_conf, limit_buy_order,
} }
freqtrade = FreqtradeBot(default_conf) freqtrade = FreqtradeBot(default_conf)
patch_get_signal(freqtrade) patch_get_signal(freqtrade)
freqtrade.strategy.min_roi_reached = lambda trade, current_profit, current_time: False freqtrade.strategy.min_roi_reached = MagicMock(return_value=False)
freqtrade.create_trade() freqtrade.create_trade()
trade = Trade.query.first() trade = Trade.query.first()
@ -1727,7 +1727,7 @@ def test_sell_profit_only_disable_loss(default_conf, limit_buy_order, fee, marke
freqtrade = FreqtradeBot(default_conf) freqtrade = FreqtradeBot(default_conf)
patch_get_signal(freqtrade) patch_get_signal(freqtrade)
freqtrade.strategy.min_roi_reached = lambda trade, current_profit, current_time: False freqtrade.strategy.min_roi_reached = MagicMock(return_value=False)
freqtrade.create_trade() freqtrade.create_trade()
@ -1757,7 +1757,7 @@ def test_ignore_roi_if_buy_signal(default_conf, limit_buy_order, fee, markets, m
} }
freqtrade = FreqtradeBot(default_conf) freqtrade = FreqtradeBot(default_conf)
patch_get_signal(freqtrade) patch_get_signal(freqtrade)
freqtrade.strategy.min_roi_reached = lambda trade, current_profit, current_time: True freqtrade.strategy.min_roi_reached = MagicMock(return_value=True)
freqtrade.create_trade() freqtrade.create_trade()
@ -1789,7 +1789,7 @@ def test_trailing_stop_loss(default_conf, limit_buy_order, fee, markets, caplog,
default_conf['trailing_stop'] = True default_conf['trailing_stop'] = True
freqtrade = FreqtradeBot(default_conf) freqtrade = FreqtradeBot(default_conf)
patch_get_signal(freqtrade) patch_get_signal(freqtrade)
freqtrade.strategy.min_roi_reached = lambda trade, current_profit, current_time: False freqtrade.strategy.min_roi_reached = MagicMock(return_value=False)
freqtrade.create_trade() freqtrade.create_trade()
@ -1824,7 +1824,7 @@ def test_trailing_stop_loss_positive(default_conf, limit_buy_order, fee, markets
default_conf['trailing_stop_positive'] = 0.01 default_conf['trailing_stop_positive'] = 0.01
freqtrade = FreqtradeBot(default_conf) freqtrade = FreqtradeBot(default_conf)
patch_get_signal(freqtrade) patch_get_signal(freqtrade)
freqtrade.strategy.min_roi_reached = lambda trade, current_profit, current_time: False freqtrade.strategy.min_roi_reached = MagicMock(return_value=False)
freqtrade.create_trade() freqtrade.create_trade()
trade = Trade.query.first() trade = Trade.query.first()
@ -1884,7 +1884,7 @@ def test_trailing_stop_loss_offset(default_conf, limit_buy_order, fee,
default_conf['trailing_stop_positive_offset'] = 0.011 default_conf['trailing_stop_positive_offset'] = 0.011
freqtrade = FreqtradeBot(default_conf) freqtrade = FreqtradeBot(default_conf)
patch_get_signal(freqtrade) patch_get_signal(freqtrade)
freqtrade.strategy.min_roi_reached = lambda trade, current_profit, current_time: False freqtrade.strategy.min_roi_reached = MagicMock(return_value=False)
freqtrade.create_trade() freqtrade.create_trade()
trade = Trade.query.first() trade = Trade.query.first()
@ -1943,7 +1943,7 @@ def test_disable_ignore_roi_if_buy_signal(default_conf, limit_buy_order,
} }
freqtrade = FreqtradeBot(default_conf) freqtrade = FreqtradeBot(default_conf)
patch_get_signal(freqtrade) patch_get_signal(freqtrade)
freqtrade.strategy.min_roi_reached = lambda trade, current_profit, current_time: True freqtrade.strategy.min_roi_reached = MagicMock(return_value=True)
freqtrade.create_trade() freqtrade.create_trade()

View File

@ -30,6 +30,7 @@ def test_sync_wallet_at_boot(mocker, default_conf):
assert freqtrade.wallets.wallets['GAS'].free == 0.260739 assert freqtrade.wallets.wallets['GAS'].free == 0.260739
assert freqtrade.wallets.wallets['GAS'].used == 0.0 assert freqtrade.wallets.wallets['GAS'].used == 0.0
assert freqtrade.wallets.wallets['GAS'].total == 0.260739 assert freqtrade.wallets.wallets['GAS'].total == 0.260739
assert freqtrade.wallets.get_free('BNT') == 1.0
mocker.patch.multiple( mocker.patch.multiple(
'freqtrade.exchange.Exchange', 'freqtrade.exchange.Exchange',
@ -56,6 +57,7 @@ def test_sync_wallet_at_boot(mocker, default_conf):
assert freqtrade.wallets.wallets['GAS'].free == 0.270739 assert freqtrade.wallets.wallets['GAS'].free == 0.270739
assert freqtrade.wallets.wallets['GAS'].used == 0.1 assert freqtrade.wallets.wallets['GAS'].used == 0.1
assert freqtrade.wallets.wallets['GAS'].total == 0.260439 assert freqtrade.wallets.wallets['GAS'].total == 0.260439
assert freqtrade.wallets.get_free('GAS') == 0.270739
def test_sync_wallet_missing_data(mocker, default_conf): def test_sync_wallet_missing_data(mocker, default_conf):
@ -84,3 +86,4 @@ def test_sync_wallet_missing_data(mocker, default_conf):
assert freqtrade.wallets.wallets['GAS'].free == 0.260739 assert freqtrade.wallets.wallets['GAS'].free == 0.260739
assert freqtrade.wallets.wallets['GAS'].used is None assert freqtrade.wallets.wallets['GAS'].used is None
assert freqtrade.wallets.wallets['GAS'].total == 0.260739 assert freqtrade.wallets.wallets['GAS'].total == 0.260739
assert freqtrade.wallets.get_free('GAS') == 0.260739

View File

@ -35,8 +35,8 @@ class Wallets(object):
return 999.9 return 999.9
balance = self.wallets.get(currency) balance = self.wallets.get(currency)
if balance and balance['free']: if balance and balance.free:
return balance['free'] return balance.free
else: else:
return 0 return 0

View File

@ -1,7 +0,0 @@
if [ ! -f "ta-lib/CHANGELOG.TXT" ]; then
tar zxvf ta-lib-0.4.0-src.tar.gz
cd ta-lib && sed -i.bak "s|0.00000001|0.000000000000000001 |g" src/ta_func/ta_utility.h && ./configure && make && sudo make install && cd ..
else
echo "TA-lib already installed, skipping download and build."
cd ta-lib && sudo make install && cd ..
fi

View File

@ -1,4 +1,4 @@
ccxt==1.17.536 ccxt==1.17.556
SQLAlchemy==1.2.14 SQLAlchemy==1.2.14
python-telegram-bot==11.1.0 python-telegram-bot==11.1.0
arrow==0.12.1 arrow==0.12.1