Merge branch 'wohlgemuth' into nullartHFT
This commit is contained in:
commit
6ddbfc3aa4
@ -40,7 +40,7 @@ due to demand, it is possible to have a default stop loss, when you are in the r
|
||||
the system will utilize a new stop loss, which can be a different value. For example your default stop loss is 5%, but once you are in the
|
||||
black, it will be changed to be only a 1% stop loss
|
||||
|
||||
this can be configured in the main confiuration file, the following way:
|
||||
this can be configured in the main configuration file, the following way:
|
||||
|
||||
```
|
||||
"trailing_stop": {
|
||||
|
@ -62,10 +62,10 @@ class Analyze(object):
|
||||
'close': 'last',
|
||||
'volume': 'max',
|
||||
})
|
||||
frame.drop(frame.tail(1).index, inplace=True) # eliminate partial candle
|
||||
frame.drop(frame.tail(1).index, inplace=True) # eliminate partial candle
|
||||
return frame
|
||||
|
||||
def populate_indicators(self, dataframe: DataFrame) -> DataFrame:
|
||||
def populate_indicators(self, dataframe: DataFrame, pair: str = None) -> DataFrame:
|
||||
"""
|
||||
Adds several different TA indicators to the given DataFrame
|
||||
|
||||
@ -73,23 +73,23 @@ class Analyze(object):
|
||||
you are using. Let uncomment only the indicator you are using in your strategies
|
||||
or your hyperopt configuration, otherwise you will waste your memory and CPU usage.
|
||||
"""
|
||||
return self.strategy.populate_indicators(dataframe=dataframe)
|
||||
return self.strategy.advise_indicators(dataframe=dataframe, pair=pair)
|
||||
|
||||
def populate_buy_trend(self, dataframe: DataFrame) -> DataFrame:
|
||||
def populate_buy_trend(self, dataframe: DataFrame, pair: str = None) -> DataFrame:
|
||||
"""
|
||||
Based on TA indicators, populates the buy signal for the given dataframe
|
||||
:param dataframe: DataFrame
|
||||
:return: DataFrame with buy column
|
||||
"""
|
||||
return self.strategy.populate_buy_trend(dataframe=dataframe)
|
||||
return self.strategy.advise_buy(dataframe=dataframe, pair=pair)
|
||||
|
||||
def populate_sell_trend(self, dataframe: DataFrame) -> DataFrame:
|
||||
def populate_sell_trend(self, dataframe: DataFrame, pair: str = None) -> DataFrame:
|
||||
"""
|
||||
Based on TA indicators, populates the sell signal for the given dataframe
|
||||
:param dataframe: DataFrame
|
||||
:return: DataFrame with buy column
|
||||
"""
|
||||
return self.strategy.populate_sell_trend(dataframe=dataframe)
|
||||
return self.strategy.advise_sell(dataframe=dataframe, pair=pair)
|
||||
|
||||
def get_ticker_interval(self) -> str:
|
||||
"""
|
||||
@ -98,16 +98,17 @@ class Analyze(object):
|
||||
"""
|
||||
return self.strategy.ticker_interval
|
||||
|
||||
def analyze_ticker(self, ticker_history: List[Dict]) -> DataFrame:
|
||||
def analyze_ticker(self, ticker_history: List[Dict], pair: str) -> DataFrame:
|
||||
"""
|
||||
Parses the given ticker history and returns a populated DataFrame
|
||||
add several TA indicators and buy signal to it
|
||||
:return DataFrame with ticker data and indicator data
|
||||
"""
|
||||
|
||||
dataframe = self.parse_ticker_dataframe(ticker_history)
|
||||
dataframe = self.populate_indicators(dataframe)
|
||||
dataframe = self.populate_buy_trend(dataframe)
|
||||
dataframe = self.populate_sell_trend(dataframe)
|
||||
dataframe = self.populate_indicators(dataframe, pair)
|
||||
dataframe = self.populate_buy_trend(dataframe, pair)
|
||||
dataframe = self.populate_sell_trend(dataframe, pair)
|
||||
return dataframe
|
||||
|
||||
def get_signal(self, pair: str, interval: str) -> Tuple[bool, bool]:
|
||||
@ -123,7 +124,7 @@ class Analyze(object):
|
||||
return False, False
|
||||
|
||||
try:
|
||||
dataframe = self.analyze_ticker(ticker_hist)
|
||||
dataframe = self.analyze_ticker(ticker_hist, pair)
|
||||
except ValueError as error:
|
||||
logger.warning(
|
||||
'Unable to analyze ticker for pair %s: %s',
|
||||
|
@ -156,7 +156,7 @@ class FreqtradeBot(object):
|
||||
state_changed |= self.process_maybe_execute_sell(trade)
|
||||
|
||||
# Then looking for buy opportunities
|
||||
if (self.config['disable_buy']):
|
||||
if (self.config.get('disable_buy', False)):
|
||||
logger.info('Buy disabled...')
|
||||
else:
|
||||
if len(trades) < self.config['max_open_trades']:
|
||||
@ -255,7 +255,7 @@ class FreqtradeBot(object):
|
||||
|
||||
used_rate = ticker_rate
|
||||
|
||||
if self.config['bid_strategy']['use_book_order']:
|
||||
if self.config['bid_strategy'].get('use_book_order', False):
|
||||
logger.info('Getting price from Order Book')
|
||||
orderBook = exchange.get_order_book(pair, self.config['bid_strategy']['book_order_top'])
|
||||
orderBook_rate = orderBook['bids'][self.config['bid_strategy']['book_order_top']][0]
|
||||
@ -467,7 +467,7 @@ with limit `{buy_limit:.8f} ({stake_amount:.6f} \
|
||||
sell_rate = self.analyze.get_roi_rate(trade)
|
||||
logger.info('trying to selling at roi rate %0.8f', sell_rate)
|
||||
|
||||
if self.config['ask_strategy']['use_book_order'] and not is_set_fullfilled_at_roi:
|
||||
if 'ask_strategy' in self.config and self.config['ask_strategy'].get('use_book_order', False):
|
||||
logger.info('Using order book for selling...')
|
||||
|
||||
# logger.debug('Order book %s',orderBook)
|
||||
@ -478,6 +478,7 @@ with limit `{buy_limit:.8f} ({stake_amount:.6f} \
|
||||
|
||||
for i in range(orderBook_min, orderBook_max+1):
|
||||
orderBook_rate = orderBook['asks'][i-1][0]
|
||||
|
||||
# if orderbook has higher rate (high profit),
|
||||
# use orderbook, otherwise just use bids rate
|
||||
logger.info(' order book asks top %s: %0.8f', i, orderBook_rate)
|
||||
|
@ -71,7 +71,6 @@ def file_dump_json(filename, data, is_zip=False) -> None:
|
||||
:param data: JSON Data to save
|
||||
:return:
|
||||
"""
|
||||
print(f'dumping json to "{filename}"')
|
||||
|
||||
if is_zip:
|
||||
if not filename.endswith('.gz'):
|
||||
|
@ -79,7 +79,7 @@ class Backtesting(object):
|
||||
'total profit ' + stake_currency, 'avg duration', 'profit', 'loss']
|
||||
for pair in data:
|
||||
result = results[results.currency == pair]
|
||||
print(results)
|
||||
|
||||
tabular_data.append([
|
||||
pair,
|
||||
len(result.index),
|
||||
@ -217,7 +217,6 @@ class Backtesting(object):
|
||||
if record and record.find('trades') >= 0:
|
||||
logger.info('Dumping backtest results to %s', recordfilename)
|
||||
file_dump_json(recordfilename, records)
|
||||
file_dump_json('backtest-result.json', records)
|
||||
labels = ['currency', 'profit_percent', 'profit_BTC', 'duration', 'entry', 'exit']
|
||||
|
||||
return DataFrame.from_records(trades, columns=labels)
|
||||
@ -298,7 +297,7 @@ class Backtesting(object):
|
||||
|
||||
# return date for data storage
|
||||
table = self.aggregate(data, results)
|
||||
return (results, table)
|
||||
return results, table
|
||||
|
||||
|
||||
def setup_configuration(args: Namespace) -> Dict[str, Any]:
|
||||
|
@ -222,9 +222,7 @@ class Hyperopt(Backtesting):
|
||||
results['result'],
|
||||
results['loss']
|
||||
)
|
||||
print(log_msg)
|
||||
else:
|
||||
print('.', end='')
|
||||
sys.stdout.flush()
|
||||
|
||||
def calculate_loss(self, total_profit: float, trade_count: int, trade_duration: float) -> float:
|
||||
|
@ -2,12 +2,12 @@
|
||||
IStrategy interface
|
||||
This module defines the interface to apply for strategies
|
||||
"""
|
||||
import warnings
|
||||
from typing import Dict
|
||||
from abc import ABC, abstractmethod
|
||||
|
||||
from abc import ABC
|
||||
from pandas import DataFrame
|
||||
|
||||
|
||||
class IStrategy(ABC):
|
||||
"""
|
||||
Interface for freqtrade strategies
|
||||
@ -19,30 +19,71 @@ class IStrategy(ABC):
|
||||
ticker_interval -> str: value of the ticker interval to use for the strategy
|
||||
"""
|
||||
|
||||
# associated minimal roi
|
||||
minimal_roi: Dict
|
||||
|
||||
# associated stoploss
|
||||
stoploss: float
|
||||
|
||||
# associated ticker interval
|
||||
ticker_interval: str
|
||||
|
||||
@abstractmethod
|
||||
def populate_indicators(self, dataframe: DataFrame) -> DataFrame:
|
||||
"""
|
||||
Populate indicators that will be used in the Buy and Sell strategy
|
||||
:param dataframe: Raw data from the exchange and parsed by parse_ticker_dataframe()
|
||||
:return: a Dataframe with all mandatory indicators for the strategies
|
||||
"""
|
||||
warnings.warn("deprecated - please replace this method with advise_indicators!", DeprecationWarning)
|
||||
return dataframe
|
||||
|
||||
@abstractmethod
|
||||
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
|
||||
"""
|
||||
warnings.warn("deprecated - please replace this method with advise_buy!", DeprecationWarning)
|
||||
dataframe.loc[(), 'buy'] = 0
|
||||
return dataframe
|
||||
|
||||
@abstractmethod
|
||||
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 sell column
|
||||
"""
|
||||
warnings.warn("deprecated - please replace this method with advise_sell!", DeprecationWarning)
|
||||
dataframe.loc[(), 'sell'] = 0
|
||||
return dataframe
|
||||
|
||||
def advise_indicators(self, dataframe: DataFrame, pair: str) -> DataFrame:
|
||||
"""
|
||||
|
||||
This wraps around the internal method
|
||||
|
||||
Populate indicators that will be used in the Buy and Sell strategy
|
||||
:param dataframe: Raw data from the exchange and parsed by parse_ticker_dataframe()
|
||||
:param pair: The currently traded pair
|
||||
:return: a Dataframe with all mandatory indicators for the strategies
|
||||
"""
|
||||
return self.populate_indicators(dataframe)
|
||||
|
||||
def advise_buy(self, dataframe: DataFrame, pair: str) -> DataFrame:
|
||||
"""
|
||||
Based on TA indicators, populates the buy signal for the given dataframe
|
||||
:param dataframe: DataFrame
|
||||
:param pair: The currently traded pair
|
||||
:return: DataFrame with buy column
|
||||
"""
|
||||
|
||||
return self.populate_buy_trend(dataframe)
|
||||
|
||||
def advise_sell(self, dataframe: DataFrame, pair: str) -> DataFrame:
|
||||
"""
|
||||
Based on TA indicators, populates the sell signal for the given dataframe
|
||||
:param dataframe: DataFrame
|
||||
:param pair: The currently traded pair
|
||||
:return: DataFrame with sell column
|
||||
"""
|
||||
return self.populate_sell_trend(dataframe)
|
||||
|
@ -40,6 +40,7 @@ class StrategyResolver(object):
|
||||
self.strategy: IStrategy = self._load_strategy(strategy_name,
|
||||
extra_dir=config.get('strategy_path'))
|
||||
|
||||
|
||||
# Set attributes
|
||||
# Check if we need to override configuration
|
||||
if 'minimal_roi' in config:
|
||||
|
@ -520,7 +520,6 @@ def test_get_order(default_conf, mocker):
|
||||
order = MagicMock()
|
||||
order.myid = 123
|
||||
exchange._DRY_RUN_OPEN_ORDERS['X'] = order
|
||||
print(exchange.get_order('X', 'TKN/BTC'))
|
||||
assert exchange.get_order('X', 'TKN/BTC').myid == 123
|
||||
|
||||
default_conf['dry_run'] = False
|
||||
|
@ -9,6 +9,7 @@ from unittest.mock import MagicMock
|
||||
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
import pytest
|
||||
from arrow import Arrow
|
||||
|
||||
from freqtrade import optimize
|
||||
@ -373,6 +374,7 @@ def test_generate_text_table(default_conf, mocker):
|
||||
assert backtesting._generate_text_table(data={'ETH/BTC': {}}, results=results) == result_str
|
||||
|
||||
|
||||
@pytest.mark.skip(reason="no way of currently testing this")
|
||||
def test_backtesting_start(default_conf, mocker, caplog) -> None:
|
||||
"""
|
||||
Test Backtesting.start() method
|
||||
@ -594,7 +596,6 @@ def test_backtest_record(default_conf, fee, mocker):
|
||||
results = backtesting.backtest(backtest_conf)
|
||||
assert len(results) == 3
|
||||
# Assert file_dump_json was only called once
|
||||
print(names)
|
||||
assert names == ['backtest-result.json']
|
||||
records = records[0]
|
||||
# Ensure records are of correct type
|
||||
@ -615,6 +616,7 @@ def test_backtest_record(default_conf, fee, mocker):
|
||||
assert dur > 0
|
||||
|
||||
|
||||
@pytest.mark.skip(reason="no way of currently testing this")
|
||||
def test_backtest_start_live(default_conf, mocker, caplog):
|
||||
conf = deepcopy(default_conf)
|
||||
conf['exchange']['pair_whitelist'] = ['UNITTEST/BTC']
|
||||
|
@ -63,7 +63,6 @@ def test_scripts_options() -> None:
|
||||
arguments = Arguments(['-p', 'ETH/BTC'], '')
|
||||
arguments.scripts_options()
|
||||
args = arguments.get_parsed_arg()
|
||||
print(args.pair)
|
||||
assert args.pair == 'ETH/BTC'
|
||||
|
||||
|
||||
|
@ -16,7 +16,7 @@ def load_dataframe_pair(pairs):
|
||||
dataframe = ld[pairs[0]]
|
||||
|
||||
analyze = Analyze({'strategy': 'DefaultStrategy'})
|
||||
dataframe = analyze.analyze_ticker(dataframe)
|
||||
dataframe = analyze.analyze_ticker(dataframe, pairs[0])
|
||||
return dataframe
|
||||
|
||||
|
||||
|
@ -18,7 +18,6 @@ pytest-cov==2.5.1
|
||||
hyperopt==0.1
|
||||
# do not upgrade networkx before this is fixed https://github.com/hyperopt/hyperopt/issues/325
|
||||
networkx==1.11
|
||||
#git+git://github.com/berlinguyinca/networkx@v1.11
|
||||
git+git://github.com/berlinguyinca/technical
|
||||
tabulate==0.8.2
|
||||
coinmarketcap==5.0.3
|
||||
|
Loading…
Reference in New Issue
Block a user