Merge pull request #29 from gcarq/backtesting

Backtesting
pull/31/merge
Janne Sinivirta 9 years ago committed by GitHub
commit e7620b46ae

@ -107,6 +107,28 @@ def execute_sell(trade: Trade, current_rate: float) -> None:
telegram.send_msg(message)
def should_sell(trade: Trade, current_rate: float, current_time: datetime) -> bool:
"""
Based an earlier trade and current price and configuration, decides whether bot should sell
:return True if bot should sell at current rate
"""
current_profit = (current_rate - trade.open_rate) / trade.open_rate
if 'stoploss' in _CONF and current_profit < float(_CONF['stoploss']):
logger.debug('Stop loss hit.')
return True
for duration, threshold in sorted(_CONF['minimal_roi'].items()):
duration, threshold = float(duration), float(threshold)
# Check if time matches and current rate is above threshold
time_diff = (current_time - trade.open_date).total_seconds() / 60
if time_diff > duration and current_profit > threshold:
return True
logger.debug('Threshold not reached. (cur_profit: %1.2f%%)', current_profit * 100.0)
return False
def handle_trade(trade: Trade) -> None:
"""
Sells the current pair if the threshold is reached and updates the trade record.
@ -117,24 +139,12 @@ def handle_trade(trade: Trade) -> None:
raise ValueError('attempt to handle closed trade: {}'.format(trade))
logger.debug('Handling open trade %s ...', trade)
# Get current rate
current_rate = exchange.get_ticker(trade.pair)['bid']
current_profit = 100.0 * ((current_rate - trade.open_rate) / trade.open_rate)
if 'stoploss' in _CONF and current_profit < float(_CONF['stoploss']) * 100.0:
logger.debug('Stop loss hit.')
current_rate = exchange.get_ticker(trade.pair)['bid']
if should_sell(trade, current_rate, datetime.utcnow()):
execute_sell(trade, current_rate)
return
for duration, threshold in sorted(_CONF['minimal_roi'].items()):
duration, threshold = float(duration), float(threshold)
# Check if time matches and current rate is above threshold
time_diff = (datetime.utcnow() - trade.open_date).total_seconds() / 60
if time_diff > duration and current_rate > (1 + threshold) * trade.open_rate:
execute_sell(trade, current_rate)
return
logger.debug('Threshold not reached. (cur_profit: %1.2f%%)', current_profit)
except ValueError:
logger.exception('Unable to handle open order')

@ -0,0 +1,66 @@
# pragma pylint: disable=missing-docstring
import unittest
from unittest.mock import patch
import os
import json
import arrow
from pandas import DataFrame
from analyze import analyze_ticker
from persistence import Trade
from main import should_sell
def print_results(results):
print('Made {} buys. Average profit {:.1f}%. Total profit was {:.3f}. Average duration {:.1f} mins.'.format(
len(results.index),
results.profit.mean() * 100.0,
results.profit.sum(),
results.duration.mean()*5
))
class TestMain(unittest.TestCase):
pairs = ['btc-neo', 'btc-eth', 'btc-omg', 'btc-edg', 'btc-pay', 'btc-pivx', 'btc-qtum', 'btc-mtl', 'btc-etc', 'btc-ltc']
conf = {
"minimal_roi": {
"2880": 0.005,
"720": 0.01,
"0": 0.02
},
"stoploss": -0.10
}
@unittest.skipIf(not os.environ.get('BACKTEST', False), "slow, should be run manually")
def test_backtest(self):
trades = []
with patch.dict('main._CONF', self.conf):
for pair in self.pairs:
with open('test/testdata/'+pair+'.json') as data_file:
data = json.load(data_file)
with patch('analyze.get_ticker', return_value=data):
with patch('arrow.utcnow', return_value=arrow.get('2017-08-20T14:50:00')):
ticker = analyze_ticker(pair)
# for each buy point
for index, row in ticker[ticker.buy == 1].iterrows():
trade = Trade(
open_rate=row['close'],
open_date=arrow.get(row['date']).datetime,
amount=1,
)
# calculate win/lose forwards from buy point
for index2, row2 in ticker[index:].iterrows():
if should_sell(trade, row2['close'], arrow.get(row2['date']).datetime):
current_profit = (row2['close'] - trade.open_rate) / trade.open_rate
trades.append((pair, current_profit, index2 - index))
break
labels = ['currency', 'profit', 'duration']
results = DataFrame.from_records(trades, columns=labels)
print('====================== BACKTESTING REPORT ================================')
for pair in self.pairs:
print('For currency {}:'.format(pair))
print_results(results[results.currency == pair])
print('TOTAL OVER ALL TRADES:')
print_results(results)

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long
Loading…
Cancel
Save