Merge branch 'develop' into StopLossSupport

This commit is contained in:
Gert 2018-06-01 19:34:39 -07:00
commit c9708442ff
20 changed files with 462 additions and 57 deletions

1
.gitignore vendored
View File

@ -6,7 +6,6 @@ config*.json
.hyperopt .hyperopt
logfile.txt logfile.txt
hyperopt_trials.pickle hyperopt_trials.pickle
user_data/
freqtrade-plot.html freqtrade-plot.html
# Byte-compiled / optimized / DLL files # Byte-compiled / optimized / DLL files

View File

@ -56,24 +56,19 @@ Windows, macOS and Linux
- [x] **Persistence**: Persistence is achieved through sqlite - [x] **Persistence**: Persistence is achieved through sqlite
- [x] **Dry-run**: Run the bot without playing money. - [x] **Dry-run**: Run the bot without playing money.
- [x] **Backtesting**: Run a simulation of your buy/sell strategy. - [x] **Backtesting**: Run a simulation of your buy/sell strategy.
- [x] **Strategy Optimization**: Optimize your buy/sell strategy - [x] **Strategy Optimization by machine learning**: Use machine learning to optimize your buy/sell
parameters with Hyperopts. strategy parameters with real exchange data.
- [x] **Whitelist crypto-currencies**: Select which crypto-currency you - [x] **Whitelist crypto-currencies**: Select which crypto-currency you want to trade.
want to trade. - [x] **Blacklist crypto-currencies**: Select which crypto-currency you want to avoid.
- [x] **Blacklist crypto-currencies**: Select which crypto-currency you
want to avoid.
- [x] **Manageable via Telegram**: Manage the bot with Telegram - [x] **Manageable via Telegram**: Manage the bot with Telegram
- [x] **Display profit/loss in fiat**: Display your profit/loss in - [x] **Display profit/loss in fiat**: Display your profit/loss in 33 fiat.
33 fiat. - [x] **Daily summary of profit/loss**: Provide a daily summary of your profit/loss.
- [x] **Daily summary of profit/loss**: Provide a daily summary - [x] **Performance status report**: Provide a performance status of your current trades.
of your profit/loss.
- [x] **Performance status report**: Provide a performance status of
your current trades.
### Exchange supported ### Exchange marketplaces supported
- [x] Bittrex - [X] [Bittrex](https://bittrex.com/)
- [ ] Binance - [X] [Binance](https://www.binance.com/)
- [ ] Others - [ ] [113 others to tests](https://github.com/ccxt/ccxt/). _(We cannot guarantee they will work)_
## Quick start ## Quick start
This quick start section is a very short explanation on how to test the This quick start section is a very short explanation on how to test the
@ -144,8 +139,9 @@ to understand the requirements before sending your pull-requests.
### Bot commands ### Bot commands
```bash ```bash
usage: main.py [-h] [-v] [--version] [-c PATH] [--dry-run-db] [--datadir PATH] usage: main.py [-h] [-v] [--version] [-c PATH] [-d PATH] [-s NAME]
[--dynamic-whitelist [INT]] [--strategy-path PATH] [--dynamic-whitelist [INT]]
[--dry-run-db]
{backtesting,hyperopt} ... {backtesting,hyperopt} ...
Simple High Frequency Trading Bot for crypto currencies Simple High Frequency Trading Bot for crypto currencies
@ -161,13 +157,18 @@ optional arguments:
--version show program's version number and exit --version show program's version number and exit
-c PATH, --config PATH -c PATH, --config PATH
specify configuration file (default: config.json) specify configuration file (default: config.json)
--dry-run-db Force dry run to use a local DB -d PATH, --datadir PATH
"tradesv3.dry_run.sqlite" instead of memory DB. Work path to backtest data (default:
only if dry_run is enabled. freqtrade/tests/testdata
--datadir PATH path to backtest data (default freqdata/tests/testdata -s NAME, --strategy NAME
specify strategy class name (default: DefaultStrategy)
--strategy-path PATH specify additional strategy lookup path
--dynamic-whitelist [INT] --dynamic-whitelist [INT]
dynamically generate and update whitelist based on 24h dynamically generate and update whitelist based on 24h
BaseVolume (Default 20 currencies) BaseVolume (Default 20 currencies)
--dry-run-db Force dry run to use a local DB
"tradesv3.dry_run.sqlite" instead of memory DB. Work
only if dry_run is enabled.
``` ```
More details on: More details on:
- [How to run the bot](https://github.com/gcarq/freqtrade/blob/develop/docs/bot-usage.md#bot-commands) - [How to run the bot](https://github.com/gcarq/freqtrade/blob/develop/docs/bot-usage.md#bot-commands)

View File

@ -53,9 +53,9 @@ python3 ./freqtrade/main.py backtesting --datadir freqtrade/tests/testdata-20180
**With a (custom) strategy file** **With a (custom) strategy file**
```bash ```bash
python3 ./freqtrade/main.py -s currentstrategy backtesting python3 ./freqtrade/main.py -s TestStrategy backtesting
``` ```
Where `-s currentstrategy` refers to a filename `currentstrategy.py` in `freqtrade/user_data/strategies` Where `-s TestStrategy` refers to the class name within the strategy file `test_strategy.py` found in the `freqtrade/user_data/strategies` directory
**Exporting trades to file** **Exporting trades to file**
```bash ```bash

View File

@ -9,7 +9,8 @@ it.
## Bot commands ## Bot commands
``` ```
usage: main.py [-h] [-c PATH] [-v] [--version] [--dynamic-whitelist [INT]] usage: main.py [-h] [-v] [--version] [-c PATH] [-d PATH] [-s NAME]
[--strategy-path PATH] [--dynamic-whitelist [INT]]
[--dry-run-db] [--dry-run-db]
{backtesting,hyperopt} ... {backtesting,hyperopt} ...
@ -26,17 +27,18 @@ optional arguments:
--version show program's version number and exit --version show program's version number and exit
-c PATH, --config PATH -c PATH, --config PATH
specify configuration file (default: config.json) specify configuration file (default: config.json)
-d PATH, --datadir PATH
path to backtest data (default:
freqtrade/tests/testdata
-s NAME, --strategy NAME -s NAME, --strategy NAME
specify strategy class name (default: DefaultStrategy) specify strategy class name (default: DefaultStrategy)
--strategy-path PATH specify additional strategy lookup path --strategy-path PATH specify additional strategy lookup path
--dry-run-db Force dry run to use a local DB
"tradesv3.dry_run.sqlite" instead of memory DB. Work
only if dry_run is enabled.
--datadir PATH
path to backtest data (default freqdata/tests/testdata
--dynamic-whitelist [INT] --dynamic-whitelist [INT]
dynamically generate and update whitelist based on 24h dynamically generate and update whitelist based on 24h
BaseVolume (Default 20 currencies) BaseVolume (Default 20 currencies)
--dry-run-db Force dry run to use a local DB
"tradesv3.dry_run.sqlite" instead of memory DB. Work
only if dry_run is enabled.
``` ```
### How to use a different config file? ### How to use a different config file?

View File

@ -24,7 +24,7 @@ The table below will list all configuration parameters.
| `stoploss` | -0.10 | No | Value of the stoploss in percent used by the bot. More information below. If set, this parameter will override `stoploss` from your strategy file. | `stoploss` | -0.10 | No | Value of the stoploss in percent used by the bot. More information below. If set, this parameter will override `stoploss` from your strategy file.
| `unfilledtimeout` | 0 | No | How long (in minutes) the bot will wait for an unfilled order to complete, after which the order will be cancelled. | `unfilledtimeout` | 0 | No | How long (in minutes) the bot will wait for an unfilled order to complete, after which the order will be cancelled.
| `bid_strategy.ask_last_balance` | 0.0 | Yes | Set the bidding price. More information below. | `bid_strategy.ask_last_balance` | 0.0 | Yes | Set the bidding price. More information below.
| `exchange.name` | bittrex | Yes | Name of the exchange class to use. | `exchange.name` | bittrex | Yes | Name of the exchange class to use. [List below](#user-content-what-values-for-exchangename).
| `exchange.key` | key | No | API key to use for the exchange. Only required when you are in production mode. | `exchange.key` | key | No | API key to use for the exchange. Only required when you are in production mode.
| `exchange.secret` | secret | No | API secret to use for the exchange. Only required when you are in production mode. | `exchange.secret` | secret | No | API secret to use for the exchange. Only required when you are in production mode.
| `exchange.pair_whitelist` | [] | No | List of currency to use by the bot. Can be overrided with `--dynamic-whitelist` param. | `exchange.pair_whitelist` | [] | No | List of currency to use by the bot. Can be overrided with `--dynamic-whitelist` param.
@ -79,6 +79,18 @@ use the `last` price and values between those interpolate between ask and last
price. Using `ask` price will guarantee quick success in bid, but bot will also price. Using `ask` price will guarantee quick success in bid, but bot will also
end up paying more then would probably have been necessary. end up paying more then would probably have been necessary.
### What values for exchange.name?
Freqtrade is based on [CCXT library](https://github.com/ccxt/ccxt) that supports 115 cryptocurrency
exchange markets and trading APIs. The complete up-to-date list can be found in the
[CCXT repo homepage](https://github.com/ccxt/ccxt/tree/master/python). However, the bot was tested
with only Bittrex and Binance.
The bot was tested with the following exchanges:
- [Bittrex](https://bittrex.com/): "bittrex"
- [Binance](https://www.binance.com/): "binance"
Feel free to test other exchanges and submit your PR to improve the bot.
### What values for fiat_display_currency? ### What values for fiat_display_currency?
`fiat_display_currency` set the fiat to use for the conversion form coin to fiat in Telegram. `fiat_display_currency` set the fiat to use for the conversion form coin to fiat in Telegram.
The valid value are: "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". The valid value are: "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".
@ -96,7 +108,7 @@ creating trades.
"dry_run": true, "dry_run": true,
``` ```
3. Remove your Bittrex API key (change them by fake api credentials) 3. Remove your Exchange API key (change them by fake api credentials)
```json ```json
"exchange": { "exchange": {
"name": "bittrex", "name": "bittrex",
@ -122,7 +134,7 @@ you run it in production mode.
"dry_run": false, "dry_run": false,
``` ```
3. Insert your Bittrex API key (change them by fake api keys) 3. Insert your Exchange API key (change them by fake api keys)
```json ```json
"exchange": { "exchange": {
"name": "bittrex", "name": "bittrex",

View File

@ -132,6 +132,13 @@ You can run a one-off container that is immediately deleted upon exiting with th
docker run --rm -v /etc/localtime:/etc/localtime:ro -v `pwd`/config.json:/freqtrade/config.json -it freqtrade docker run --rm -v /etc/localtime:/etc/localtime:ro -v `pwd`/config.json:/freqtrade/config.json -it freqtrade
``` ```
There is known issue in OSX Docker versions after 17.09.1, whereby /etc/localtime cannot be shared causing Docker to not start. A work-around for this is to start with the following cmd.
```bash
docker run --rm -e TZ=`ls -la /etc/localtime | cut -d/ -f8-9` -v `pwd`/config.json:/freqtrade/config.json -it freqtrade
```
More information on this docker issue and work-around can be read here: https://github.com/docker/for-mac/issues/2396
In this example, the database will be created inside the docker instance and will be lost when you will refresh your image. In this example, the database will be created inside the docker instance and will be lost when you will refresh your image.

View File

@ -8,6 +8,7 @@ import time
from typing import Dict from typing import Dict
from coinmarketcap import Market from coinmarketcap import Market
from requests.exceptions import RequestException
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -94,8 +95,8 @@ class CryptoToFiatConverter(object):
coinlistings = self._coinmarketcap.listings() coinlistings = self._coinmarketcap.listings()
self._cryptomap = dict(map(lambda coin: (coin["symbol"], str(coin["id"])), self._cryptomap = dict(map(lambda coin: (coin["symbol"], str(coin["id"])),
coinlistings["data"])) coinlistings["data"]))
except ValueError: except (ValueError, RequestException) as e:
logger.error("Could not load FIAT Cryptocurrency map") logger.error("Could not load FIAT Cryptocurrency map for the following problem: %s", e)
def convert_amount(self, crypto_amount: float, crypto_symbol: str, fiat_symbol: str) -> float: def convert_amount(self, crypto_amount: float, crypto_symbol: str, fiat_symbol: str) -> float:
""" """

View File

@ -61,6 +61,7 @@ def set_loggers() -> None:
:return: None :return: None
""" """
logging.getLogger('requests.packages.urllib3').setLevel(logging.INFO) logging.getLogger('requests.packages.urllib3').setLevel(logging.INFO)
logging.getLogger('ccxt.base.exchange').setLevel(logging.INFO)
logging.getLogger('telegram').setLevel(logging.INFO) logging.getLogger('telegram').setLevel(logging.INFO)

View File

@ -29,7 +29,7 @@ def trim_tickerlist(tickerlist: List[Dict], timerange: Tuple[Tuple, int, int]) -
if stype[0] == 'index': if stype[0] == 'index':
start_index = start start_index = start
elif stype[0] == 'date': elif stype[0] == 'date':
while tickerlist[start_index][0] < start * 1000: while start_index < len(tickerlist) and tickerlist[start_index][0] < start * 1000:
start_index += 1 start_index += 1
if stype[1] == 'line': if stype[1] == 'line':
@ -37,7 +37,7 @@ def trim_tickerlist(tickerlist: List[Dict], timerange: Tuple[Tuple, int, int]) -
if stype[1] == 'index': if stype[1] == 'index':
stop_index = stop stop_index = stop
elif stype[1] == 'date': elif stype[1] == 'date':
while tickerlist[stop_index-1][0] > stop * 1000: while stop_index > 0 and tickerlist[stop_index-1][0] > stop * 1000:
stop_index -= 1 stop_index -= 1
if start_index > stop_index: if start_index > stop_index:
@ -100,15 +100,11 @@ def load_data(datadir: str,
for pair in _pairs: for pair in _pairs:
pairdata = load_tickerdata_file(datadir, pair, ticker_interval, timerange=timerange) pairdata = load_tickerdata_file(datadir, pair, ticker_interval, timerange=timerange)
if not pairdata: if pairdata:
# download the tickerdata from exchange result[pair] = pairdata
download_backtesting_testdata(datadir, else:
pair=pair, logger.warn('No data for pair %s, use --update-pairs-cached to download the data', pair)
tick_interval=ticker_interval,
timerange=timerange)
# and retry reading the pair
pairdata = load_tickerdata_file(datadir, pair, ticker_interval, timerange=timerange)
result[pair] = pairdata
return result return result

View File

@ -98,10 +98,11 @@ class RPC(object):
trade.id, trade.id,
trade.pair, trade.pair,
shorten_date(arrow.get(trade.open_date).humanize(only_distance=True)), shorten_date(arrow.get(trade.open_date).humanize(only_distance=True)),
'{:.2f}%'.format(100 * trade.calc_profit_percent(current_rate)) '{:.2f}%'.format(100 * trade.calc_profit_percent(current_rate)),
'{:.6f}'.format(trade.amount * current_rate)
]) ])
columns = ['ID', 'Pair', 'Since', 'Profit'] columns = ['ID', 'Pair', 'Since', 'Profit', 'Value']
df_statuses = DataFrame.from_records(trades_list, columns=columns) df_statuses = DataFrame.from_records(trades_list, columns=columns)
df_statuses = df_statuses.set_index(columns[0]) df_statuses = df_statuses.set_index(columns[0])
# The style used throughout is to return a tuple # The style used throughout is to return a tuple

View File

@ -99,7 +99,20 @@ def test_load_data_with_new_pair_1min(ticker_history, mocker, caplog) -> None:
file = os.path.join(os.path.dirname(__file__), '..', 'testdata', 'MEME_BTC-1m.json') file = os.path.join(os.path.dirname(__file__), '..', 'testdata', 'MEME_BTC-1m.json')
_backup_file(file) _backup_file(file)
optimize.load_data(None, ticker_interval='1m', pairs=['MEME/BTC']) # do not download a new pair if refresh_pairs isn't set
optimize.load_data(None,
ticker_interval='1m',
refresh_pairs=False,
pairs=['MEME/BTC'])
assert os.path.isfile(file) is False
assert log_has('No data for pair MEME/BTC, use --update-pairs-cached to download the data',
caplog.record_tuples)
# download a new pair if refresh_pairs is set
optimize.load_data(None,
ticker_interval='1m',
refresh_pairs=True,
pairs=['MEME/BTC'])
assert os.path.isfile(file) is True assert os.path.isfile(file) is True
assert log_has('Download the pair: "MEME/BTC", Interval: 1m', caplog.record_tuples) assert log_has('Download the pair: "MEME/BTC", Interval: 1m', caplog.record_tuples)
_clean_test_file(file) _clean_test_file(file)

View File

@ -106,6 +106,7 @@ def test_rpc_status_table(default_conf, ticker, fee, mocker) -> None:
assert 'just now' in result['Since'].all() assert 'just now' in result['Since'].all()
assert 'ETH/BTC' in result['Pair'].all() assert 'ETH/BTC' in result['Pair'].all()
assert '-0.59%' in result['Profit'].all() assert '-0.59%' in result['Profit'].all()
assert 'Value' in result
def test_rpc_daily_profit(default_conf, update, ticker, fee, def test_rpc_daily_profit(default_conf, update, ticker, fee,

View File

@ -6,6 +6,8 @@ from unittest.mock import MagicMock
import pytest import pytest
from requests.exceptions import RequestException
from freqtrade.fiat_convert import CryptoFiat, CryptoToFiatConverter from freqtrade.fiat_convert import CryptoFiat, CryptoToFiatConverter
from freqtrade.tests.conftest import patch_coinmarketcap from freqtrade.tests.conftest import patch_coinmarketcap
@ -133,6 +135,21 @@ def test_loadcryptomap(mocker):
assert fiat_convert._cryptomap["BTC"] == "1" assert fiat_convert._cryptomap["BTC"] == "1"
def test_fiat_init_network_exception(mocker):
# Because CryptoToFiatConverter is a Singleton we reset the listings
listmock = MagicMock(side_effect=RequestException)
mocker.patch.multiple(
'freqtrade.fiat_convert.Market',
listings=listmock,
)
# with pytest.raises(RequestEsxception):
fiat_convert = CryptoToFiatConverter()
fiat_convert._cryptomap = {}
fiat_convert._load_cryptomap()
assert len(fiat_convert._cryptomap) == 0
def test_fiat_convert_without_network(): def test_fiat_convert_without_network():
# Because CryptoToFiatConverter is a Singleton we reset the value of _coinmarketcap # Because CryptoToFiatConverter is a Singleton we reset the value of _coinmarketcap

View File

@ -1,5 +1,5 @@
ccxt==1.14.24 ccxt==1.14.96
SQLAlchemy==1.2.7 SQLAlchemy==1.2.8
python-telegram-bot==10.1.0 python-telegram-bot==10.1.0
arrow==0.12.1 arrow==0.12.1
cachetools==2.1.0 cachetools==2.1.0
@ -12,7 +12,7 @@ scipy==1.1.0
jsonschema==2.6.0 jsonschema==2.6.0
numpy==1.14.3 numpy==1.14.3
TA-Lib==0.4.17 TA-Lib==0.4.17
pytest==3.5.1 pytest==3.6.0
pytest-mock==1.10.0 pytest-mock==1.10.0
pytest-cov==2.5.1 pytest-cov==2.5.1
hyperopt==0.1 hyperopt==0.1

View File

@ -159,6 +159,15 @@ def plot_analyzed_dataframe(args: Namespace) -> None:
fillcolor="rgba(0,176,246,0.2)", fillcolor="rgba(0,176,246,0.2)",
line={'color': "transparent"}, line={'color': "transparent"},
) )
bb_middle = go.Scatter(
x=data.date,
y=data.bb_middleband,
name='BB middle',
fill="tonexty",
fillcolor="rgba(0,176,246,0.2)",
line={'color': "red"},
)
macd = go.Scattergl(x=data['date'], y=data['macd'], name='MACD') macd = go.Scattergl(x=data['date'], y=data['macd'], name='MACD')
macdsignal = go.Scattergl(x=data['date'], y=data['macdsignal'], name='MACD signal') macdsignal = go.Scattergl(x=data['date'], y=data['macdsignal'], name='MACD signal')
volume = go.Bar(x=data['date'], y=data['volume'], name='Volume') volume = go.Bar(x=data['date'], y=data['volume'], name='Volume')
@ -173,7 +182,9 @@ def plot_analyzed_dataframe(args: Namespace) -> None:
fig.append_trace(candles, 1, 1) fig.append_trace(candles, 1, 1)
fig.append_trace(bb_lower, 1, 1) fig.append_trace(bb_lower, 1, 1)
fig.append_trace(bb_middle, 1, 1)
fig.append_trace(bb_upper, 1, 1) fig.append_trace(bb_upper, 1, 1)
fig.append_trace(buys, 1, 1) fig.append_trace(buys, 1, 1)
fig.append_trace(sells, 1, 1) fig.append_trace(sells, 1, 1)
fig.append_trace(volume, 2, 1) fig.append_trace(volume, 2, 1)

View File

@ -89,13 +89,21 @@ function config_generator () {
echo "General configuration" echo "General configuration"
echo "-------------------------" echo "-------------------------"
echo echo
read -p "Max open trades: (Default: 3) " max_trades default_max_trades=3
read -p "Max open trades: (Default: $default_max_trades) " max_trades
max_trades=${max_trades:-$default_max_trades}
read -p "Stake amount: (Default: 0.05) " stake_amount default_stake_amount=0.05
read -p "Stake amount: (Default: $default_stake_amount) " stake_amount
stake_amount=${stake_amount:-$default_stake_amount}
read -p "Stake currency: (Default: BTC) " stake_currency default_stake_currency="BTC"
read -p "Stake currency: (Default: $default_stake_currency) " stake_currency
stake_currency=${stake_currency:-$default_stake_currency}
read -p "Fiat currency: (Default: USD) " fiat_currency default_fiat_currency="USD"
read -p "Fiat currency: (Default: $default_fiat_currency) " fiat_currency
fiat_currency=${fiat_currency:-$default_fiat_currency}
echo "------------------------" echo "------------------------"
echo "Bittrex config generator" echo "Bittrex config generator"

View File

@ -0,0 +1,94 @@
# --- Do not remove these libs ---
from freqtrade.strategy.interface import IStrategy
from typing import Dict, List
from hyperopt import hp
from functools import reduce
from pandas import DataFrame
# --------------------------------
import talib.abstract as ta
import freqtrade.vendor.qtpylib.indicators as qtpylib
import numpy # noqa
class Long(IStrategy):
"""
author@: Gert Wohlgemuth
"""
# Minimal ROI designed for the strategy.
# This attribute will be overridden if the config file contains "minimal_roi"
minimal_roi = {
"60": 0.05,
"30": 0.06,
"20": 0.07,
"0": 0.08
}
# Optimal stoploss designed for the strategy
# This attribute will be overridden if the config file contains "stoploss"
stoploss = -0.15
# Optimal ticker interval for the strategy
ticker_interval = 60
def populate_indicators(self, dataframe: DataFrame) -> DataFrame:
macd = ta.MACD(dataframe)
dataframe['macd'] = macd['macd']
dataframe['macdsignal'] = macd['macdsignal']
dataframe['macdhist'] = macd['macdhist']
dataframe['cci'] = ta.CCI(dataframe)
dataframe['tema'] = ta.TEMA(dataframe, timeperiod=50)
bollinger = qtpylib.bollinger_bands(qtpylib.typical_price(dataframe), window=20, stds=2)
dataframe['bb_lowerband'] = bollinger['lower']
dataframe['bb_middleband'] = bollinger['mid']
dataframe['bb_upperband'] = bollinger['upper']
# RSI
dataframe['rsi'] = ta.RSI(dataframe)
# Inverse Fisher transform on RSI, values [-1.0, 1.0] (https://goo.gl/2JGGoy)
rsi = 0.1 * (dataframe['rsi'] - 50)
dataframe['fisher_rsi'] = (numpy.exp(2 * rsi) - 1) / (numpy.exp(2 * rsi) + 1)
# SAR Parabol
dataframe['sar'] = ta.SAR(dataframe)
return dataframe
def populate_buy_trend(self, dataframe: DataFrame) -> DataFrame:
"""
Based on TA indicators, populates the buy signal for the given dataframe
:param dataframe: DataFrame
:return: DataFrame with buy column
"""
dataframe.loc[
(
(dataframe['macd'] > dataframe['macdsignal']) &
(dataframe['macd'] > 0) &
(dataframe['cci'] <= 0.0)
),
'buy'] = 1
return dataframe
def populate_sell_trend(self, dataframe: DataFrame) -> DataFrame:
"""
Based on TA indicators, populates the sell signal for the given dataframe
:param dataframe: DataFrame
:return: DataFrame with buy column
"""
dataframe.loc[
(
# (dataframe['tema'] < dataframe['close'])
(dataframe['sar'] > dataframe['close']) &
(dataframe['fisher_rsi'] > 0.3)
),
'sell'] = 1
return dataframe

View File

@ -0,0 +1,75 @@
# --- Do not remove these libs ---
from freqtrade.strategy.interface import IStrategy
from typing import Dict, List
from hyperopt import hp
from functools import reduce
from pandas import DataFrame
# --------------------------------
import talib.abstract as ta
import freqtrade.vendor.qtpylib.indicators as qtpylib
class Quickie(IStrategy):
"""
author@: Gert Wohlgemuth
idea:
momentum based strategie. The main idea is that it closes trades very quickly, while avoiding excessive losses. Hence a rather moderate stop loss in this case
"""
# Minimal ROI designed for the strategy.
# This attribute will be overridden if the config file contains "minimal_roi"
minimal_roi = {
"60": 0.005,
"10": 0.01,
}
# Optimal stoploss designed for the strategy
# This attribute will be overridden if the config file contains "stoploss"
stoploss = -0.25
# Optimal ticker interval for the strategy
ticker_interval = 5
def populate_indicators(self, dataframe: DataFrame) -> DataFrame:
dataframe['tema'] = ta.TEMA(dataframe, timeperiod=9)
dataframe['adx'] = ta.ADX(dataframe)
dataframe['sma_200'] = ta.SMA(dataframe, timeperiod=200)
dataframe['sma_50'] = ta.SMA(dataframe, timeperiod=50)
# required for graphing
bollinger = qtpylib.bollinger_bands(dataframe['close'], window=20, stds=2)
dataframe['bb_lowerband'] = bollinger['lower']
dataframe['bb_middleband'] = bollinger['mid']
dataframe['bb_upperband'] = bollinger['upper']
return dataframe
def populate_buy_trend(self, dataframe: DataFrame) -> DataFrame:
dataframe.loc[
(
(
(dataframe['adx'] > 30) &
(dataframe['tema'] < dataframe['bb_middleband']) &
(dataframe['tema'] > dataframe['tema'].shift(1)) &
(dataframe['sma_200'] > dataframe['close'])
)
),
'buy'] = 1
return dataframe
def populate_sell_trend(self, dataframe: DataFrame) -> DataFrame:
dataframe.loc[
(
(
(dataframe['adx'] > 70) &
(dataframe['tema'] > dataframe['bb_middleband']) &
(dataframe['tema'] < dataframe['tema'].shift(1))
)
),
'sell'] = 1
return dataframe

View File

@ -0,0 +1,76 @@
# --- Do not remove these libs ---
from freqtrade.strategy.interface import IStrategy
from typing import Dict, List
from hyperopt import hp
from functools import reduce
from pandas import DataFrame
# --------------------------------
import talib.abstract as ta
import freqtrade.vendor.qtpylib.indicators as qtpylib
class Simple(IStrategy):
"""
author@: Gert Wohlgemuth
idea:
this strategy is based on the book, 'The Simple Strategy' and can be found in detail here:
https://www.amazon.com/Simple-Strategy-Powerful-Trading-Futures-ebook/dp/B00E66QPCG/ref=sr_1_1?ie=UTF8&qid=1525202675&sr=8-1&keywords=the+simple+strategy
"""
# Minimal ROI designed for the strategy.
# since this strategy is planned around 5 minutes, we assume any time we have a 5% profit we should call it a day
# This attribute will be overridden if the config file contains "minimal_roi"
minimal_roi = {
"0": 0.01
}
# Optimal stoploss designed for the strategy
# This attribute will be overridden if the config file contains "stoploss"
stoploss = -0.25
# Optimal ticker interval for the strategy
ticker_interval = 5
def populate_indicators(self, dataframe: DataFrame) -> DataFrame:
# MACD
macd = ta.MACD(dataframe)
dataframe['macd'] = macd['macd']
dataframe['macdsignal'] = macd['macdsignal']
dataframe['macdhist'] = macd['macdhist']
# RSI
dataframe['rsi'] = ta.RSI(dataframe, timeperiod=7)
# required for graphing
bollinger = qtpylib.bollinger_bands(dataframe['close'], window=12, stds=2)
dataframe['bb_lowerband'] = bollinger['lower']
dataframe['bb_upperband'] = bollinger['upper']
dataframe['bb_middleband'] = bollinger['mid']
return dataframe
def populate_buy_trend(self, dataframe: DataFrame) -> DataFrame:
dataframe.loc[
(
(
(dataframe['macd'] > 0) # over 0
& (dataframe['macd'] > dataframe['macdsignal']) # over signal
& (dataframe['bb_upperband'] > dataframe['bb_upperband'].shift(1)) # pointed up
& (dataframe['rsi'] > 70) # optional filter, need to investigate
)
),
'buy'] = 1
return dataframe
def populate_sell_trend(self, dataframe: DataFrame) -> DataFrame:
# different strategy used for sell points, due to be able to duplicate it to 100%
dataframe.loc[
(
(dataframe['rsi'] > 80)
),
'sell'] = 1
return dataframe

View File

@ -0,0 +1,90 @@
# --- Do not remove these libs ---
from freqtrade.strategy.interface import IStrategy
from typing import Dict, List
from hyperopt import hp
from functools import reduce
from pandas import DataFrame
# --------------------------------
import talib.abstract as ta
import freqtrade.vendor.qtpylib.indicators as qtpylib
class ZLC(IStrategy):
"""
author@: Gert Wohlgemuth
"""
# Minimal ROI designed for the strategy.
# This attribute will be overridden if the config file contains "minimal_roi"
minimal_roi = {
"60": 0.01,
"30": 0.03,
"20": 0.04,
"0": 0.01
}
# Optimal stoploss designed for the strategy
# This attribute will be overridden if the config file contains "stoploss"
stoploss = -0.3
# Optimal ticker interval for the strategy
ticker_interval = 5
def populate_indicators(self, dataframe: DataFrame) -> DataFrame:
dataframe['cci-slow'] = ta.CCI(dataframe, timeperiod=25)
dataframe['cci-fast'] = ta.CCI(dataframe, timeperiod=50)
dataframe['expo'] = ta.EMA(dataframe, timeperiod=35)
# required for graphing
bollinger = qtpylib.bollinger_bands(qtpylib.typical_price(dataframe), window=20, stds=2)
dataframe['bb_lowerband'] = bollinger['lower']
dataframe['bb_middleband'] = bollinger['mid']
dataframe['bb_upperband'] = bollinger['upper']
macd = ta.MACD(dataframe)
dataframe['macd'] = macd['macd']
dataframe['macdsignal'] = macd['macdsignal']
dataframe['macdhist'] = macd['macdhist']
return dataframe
def populate_buy_trend(self, dataframe: DataFrame) -> DataFrame:
"""
Based on TA indicators, populates the buy signal for the given dataframe
:param dataframe: DataFrame
:return: DataFrame with buy column
"""
dataframe.loc[
(
#don't buy on peak tops
(dataframe['close'] < dataframe['bb_middleband'])
# this is the main concept of evaluating buys
& (dataframe['cci-fast'] > 0)
& (dataframe['cci-slow'] > 0)
& (dataframe['close'] > dataframe['expo'])
)
,
'buy'] = 1
return dataframe
def populate_sell_trend(self, dataframe: DataFrame) -> DataFrame:
"""
Based on TA indicators, populates the sell signal for the given dataframe
:param dataframe: DataFrame
:return: DataFrame with buy column
"""
dataframe.loc[
(dataframe['close'] >= dataframe['bb_upperband']) |
(
(dataframe['cci-fast'] < 0)
& (dataframe['cci-slow'] < 0)
& (dataframe['close'] < dataframe['expo'])
)
,
'sell'] = 0
return dataframe