This commit is contained in:
creslinux 2018-07-15 17:03:47 +00:00
parent 4e68362d46
commit a8b62a21cc

View File

@ -190,7 +190,6 @@ class Backtesting(object):
return btr
return None
@profile
def backtest(self, args: Dict) -> DataFrame:
"""
Implements backtesting functionality
@ -233,7 +232,13 @@ class Backtesting(object):
last_bslap_results = bslap_results
bslap_results = last_bslap_results + bslap_pair_results
# Switch List of Trade Dicts (bslap_results) to Dataframe
# Fill missing, calculable columns, profit, duration , abs etc.
bslap_results_df = DataFrame(bslap_results, columns=BacktestResult._fields)
bslap_results_df = self.vector_fill_results_table(bslap_results_df)
print(bslap_results_df.dtypes)
return bslap_results_df
########################### Original BT loop
@ -283,6 +288,69 @@ class Backtesting(object):
# return DataFrame.from_records(trades, columns=BacktestResult._fields)
######################## Original BT loop end
def vector_fill_results_table(self, bslap_results_df: DataFrame):
"""
The Results frame contains a number of columns that are calculable
from othe columns. These are left blank till all rows are added,
to be populated in single vector calls.
Columns to be populated are:
- Profit
- trade duration
- profit abs
:param bslap_results Dataframe
:return: bslap_results Dataframe
"""
import pandas as pd
debug = True
# stake and fees
stake = self.config.get('stake_amount')
# TODO grab these from the environment, do not hard set
open_fee = 0.05
close_fee = 0.05
if debug:
print("Stake is,", stake, "the sum of currency to spend per trade")
print("The open fee is", open_fee, "The close fee is", close_fee)
if debug:
from pandas import set_option
set_option('display.max_rows', 5000)
set_option('display.max_columns', 8)
pd.set_option('display.width', 1000)
pd.set_option('max_colwidth', 40)
pd.set_option('precision', 12)
# Align with BT
bslap_results_df['open_time'] = pd.to_datetime(bslap_results_df['open_time'])
bslap_results_df['close_time'] = pd.to_datetime(bslap_results_df['close_time'])
# Populate duration
bslap_results_df['trade_duration'] = bslap_results_df['close_time'] - bslap_results_df['open_time']
if debug:
print(bslap_results_df[['open_time', 'close_time', 'trade_duration']])
## Spends, Takes, Profit, Absolute Profit
# Buy Price
bslap_results_df['buy_sum'] = stake * bslap_results_df['open_rate']
bslap_results_df['buy_fee'] = bslap_results_df['buy_sum'] * open_fee
bslap_results_df['buy_spend'] = bslap_results_df['buy_sum'] + bslap_results_df['buy_fee']
# Sell price
bslap_results_df['sell_sum'] = stake * bslap_results_df['close_rate']
bslap_results_df['sell_fee'] = bslap_results_df['sell_sum'] * close_fee
bslap_results_df['sell_take'] = bslap_results_df['sell_sum'] - bslap_results_df['sell_fee']
# profit_percent
bslap_results_df['profit_percent'] = bslap_results_df['sell_take'] / bslap_results_df['buy_spend'] - 1
# Absolute profit
bslap_results_df['profit_abs'] = bslap_results_df['sell_take'] - bslap_results_df['buy_spend']
if debug:
print("\n")
print(bslap_results_df[['buy_spend', 'sell_take', 'profit_percent', 'profit_abs']])
return bslap_results_df
def np_get_t_open_ind(self, np_buy_arr, t_exit_ind: int):
import utils_find_1st as utf1st
"""
@ -301,6 +369,7 @@ class Backtesting(object):
t_open_ind = t_open_ind + t_exit_ind # Align numpy index
return t_open_ind
@profile
def backslap_pair(self, ticker_data, pair):
import pandas as pd
import numpy as np
@ -316,19 +385,10 @@ class Backtesting(object):
# Read Stop Loss Values and Stake
stop = self.stop_loss_value
p_stop = (stop + 1) # What stop really means, e.g 0.01 is 0.99 of price
stake = self.config.get('stake_amount')
# Set fees
# TODO grab these from the environment, do not hard set
# Fees
open_fee = 0.05
close_fee = 0.05
if debug:
print("Stop is ", stop, "value from stragey file")
print("p_stop is", p_stop, "value used to multiply to entry price")
print("Stake is,", stake, "the sum of currency to spend per trade")
print("The open fee is", open_fee, "The close fee is", close_fee)
if debug:
from pandas import set_option
@ -395,6 +455,12 @@ class Backtesting(object):
# buy 0 - open 1 - close 2 - sell 3 - high 4 - low 5
np_bslap = np.array(bslap[['buy', 'open', 'close', 'sell', 'high', 'low']])
# Build a numpy list of date-times.
# We use these when building the trade
# The rationale is to address a value from a pandas cell is thousands of
# times more expensive. Processing time went X25 when trying to use any data from pandas
np_bslap_dates = bslap['date'].values
loop: int = 0 # how many time around the loop
t_exit_ind = 0 # Start loop from first index
t_exit_last = 0 # To test for exit
@ -660,6 +726,10 @@ class Backtesting(object):
Add trade to backtest looking results list of dicts
Loop back to look for more trades.
"""
if debug_timing:
t_t = f(st)
print("8a-IfEls", str.format('{0:.17f}', t_t))
st = s()
# Index will change if incandle stop or look back as close Open and Sell
if t_exit_type == 'stop':
close_index: int = t_exit_ind + 1
@ -668,39 +738,56 @@ class Backtesting(object):
else:
close_index: int = t_exit_ind + 1
# Munge the date / delta (bt already date formats...just subract)
trade_start = bslap.iloc[t_open_ind + 1]['date']
trade_end = bslap.iloc[close_index]['date']
# def __datetime(date_str):
# return datetime.strptime(date_str, '%Y-%m-%d %H:%M:%S+00:00')
trade_mins = (trade_end - trade_start).total_seconds() / 60
if debug_timing:
t_t = f(st)
print("8b-Index", str.format('{0:.17f}', t_t))
st = s()
# Profit ABS.
# sumrecieved((rate * numTokens) * fee) - sumpaid ((rate * numTokens) * fee)
sumpaid: float = (np_trade_enter_price * stake)
sumpaid_fee: float = sumpaid * open_fee
sumrecieved: float = (np_trade_exit_price * stake)
sumrecieved_fee: float = sumrecieved * close_fee
profit_abs: float = sumrecieved - sumpaid - sumpaid_fee - sumrecieved_fee
# # Profit ABS.
# # sumrecieved((rate * numTokens) * fee) - sumpaid ((rate * numTokens) * fee)
# sumpaid: float = (np_trade_enter_price * stake)
# sumpaid_fee: float = sumpaid * open_fee
# sumrecieved: float = (np_trade_exit_price * stake)
# sumrecieved_fee: float = sumrecieved * close_fee
# profit_abs: float = sumrecieved - sumpaid - sumpaid_fee - sumrecieved_fee
if debug_timing:
t_t = f(st)
print("8d---ABS", str.format('{0:.17f}', t_t))
st = s()
# Build trade dictionary
## In general if a field can be calculated later from other fields leave blank here
## Its X(numer of trades faster) to calc all in a single vector than 1 trade at a time
# build trade dictionary
bslap_result["pair"] = pair
bslap_result["profit_percent"] = (np_trade_exit_price - np_trade_enter_price) / np_trade_enter_price
bslap_result["profit_abs"] = round(profit_abs, 15)
bslap_result["open_time"] = trade_start
bslap_result["close_time"] = trade_end
bslap_result["profit_percent"] = "1" # To be 1 vector calc across trades when loop complete
bslap_result["profit_abs"] = "1" # To be 1 vector calc across trades when loop complete
bslap_result["open_time"] = np_bslap_dates[t_open_ind + 1] # use numpy array, pandas 20x slower
bslap_result["close_time"] = np_bslap_dates[close_index] # use numpy array, pandas 20x slower
bslap_result["open_index"] = t_open_ind + 2 # +1 between np and df, +1 as we buy on next.
bslap_result["close_index"] = close_index
bslap_result["trade_duration"] = trade_mins
bslap_result["trade_duration"] = "1" # To be 1 vector calc across trades when loop complete
bslap_result["open_at_end"] = False
bslap_result["open_rate"] = round(np_trade_enter_price, 15)
bslap_result["close_rate"] = round(np_trade_exit_price, 15)
#bslap_result["exit_type"] = t_exit_type
bslap_result["exit_type"] = t_exit_type
if debug_timing:
t_t = f(st)
print("8e-trade", str.format('{0:.17f}', t_t))
st = s()
# Add trade dictionary to list
bslap_pair_results.append(bslap_result)
if debug:
print(bslap_pair_results)
if debug_timing:
t_t = f(st)
print("8f--list", str.format('{0:.17f}', t_t))
st = s()
"""
Loop back to start. t_exit_last becomes where loop
will seek to open new trades from.