Edge calculation refactored: removing redundant calculations

This commit is contained in:
misagh 2018-11-02 18:07:38 +01:00
parent 8a316aba35
commit 2f6aafe66c
1 changed files with 37 additions and 49 deletions

View File

@ -215,15 +215,11 @@ class Edge():
def _process_expectancy(self, results: DataFrame) -> list:
"""
This is a temporary version of edge positioning calculation.
The function will be eventually moved to a plugin called Edge in order
to calculate necessary WR, RRR and
other indictaors related to money management periodically (each X minutes)
and keep it in a storage.
This calculates WinRate, Required Risk Reward, Risk Reward and Expectancy of all pairs
The calulation will be done per pair and per strategy.
"""
# Removing pairs having less than min_trades_number
min_trades_number = self.edge_config.get('min_trade_number', 15)
min_trades_number = self.edge_config.get('min_trade_number', 10)
results = results.groupby(['pair', 'stoploss']).filter(lambda x: len(x) > min_trades_number)
###################################
@ -242,61 +238,53 @@ class Edge():
results = results[results.trade_duration < max_trade_duration]
#######################################################################
# Win Rate is the number of profitable trades
# Divided by number of trades
def winrate(x):
x = x[x > 0].count() / x.count()
return x
#############################
# Risk Reward Ratio
# 1 / ((loss money / losing trades) / (gained money / winning trades))
def risk_reward_ratio(x):
x = abs(1 / ((x[x < 0].sum() / x[x < 0].count()) / (x[x > 0].sum() / x[x > 0].count())))
return x
##############################
# Required Risk Reward
# (1/(winrate - 1)
def required_risk_reward(x):
x = (1 / (x[x > 0].count() / x.count()) - 1)
return x
##############################
# Expectancy
# Tells you the interest percentage you should hope
# E.x. if expectancy is 0.35, on $1 trade you should expect a target of $1.35
def expectancy(x):
average_win = float(x[x > 0].sum() / x[x > 0].count())
average_loss = float(abs(x[x < 0].sum() / x[x < 0].count()))
winrate = float(x[x > 0].count() / x.count())
x = ((1 + average_win / average_loss) * winrate) - 1
return x
##############################
if results.empty:
return []
groupby_aggregator = {
'profit_abs': [
winrate,
risk_reward_ratio,
required_risk_reward,
expectancy,
'count'],
'trade_duration': ['mean']}
('nb_trades', 'count'), # number of all trades
('profit_sum', lambda x: x[x > 0].sum()), # cumulative profit of all winning trades
('loss_sum', lambda x: abs(x[x < 0].sum())), # cumulative loss of all losing trades
('nb_win_trades', lambda x: x[x > 0].count()) # number of winning trades
],
'trade_duration': [('avg_trade_duration', 'mean')]
}
final = results.groupby(['pair', 'stoploss'])['profit_abs', 'trade_duration'].agg(
# Group by (pair and stoploss) the applying above aggregator
df = results.groupby(['pair', 'stoploss'])['profit_abs', 'trade_duration'].agg(
groupby_aggregator).reset_index(col_level=1)
final.columns = final.columns.droplevel(0)
final = final.sort_values(by=['expectancy', 'stoploss'], ascending=False).groupby(
# Dropping level 0 as we don't need it
df.columns = df.columns.droplevel(0)
# Calculating number of losing trades, average win and average loss
df['nb_loss_trades'] = df['nb_trades'] - df['nb_win_trades']
df['average_win'] = df['profit_sum'] / df['nb_win_trades']
df['average_loss'] = df['loss_sum'] / df['nb_loss_trades']
# Win rate = number of profitable trades / number of trades
df['winrate'] = df['nb_win_trades'] / df['nb_trades']
# risk_reward_ratio = 1 / (average loss / average win)
df['risk_reward_ratio'] = 1 / (df['average_loss'] / df['average_win'])
# required_risk_reward = (1 / winrate) - 1
df['required_risk_reward'] = (1 / df['winrate']) - 1
# expectancy = ((1 + average_win/average_loss) * winrate) - 1
df['expectancy'] = ((1 + df['average_win'] / df['average_loss']) * df['winrate']) - 1
# sort by expectancy and stoploss
df = df.sort_values(by=['expectancy', 'stoploss'], ascending=False).groupby(
'pair').first().sort_values(by=['expectancy'], ascending=False).reset_index()
final.rename(columns={'mean': 'avg_duration(min)'}, inplace=True)
# dropping unecessary columns
df.drop(columns=['nb_loss_trades', 'nb_win_trades', 'average_win', 'average_loss',
'profit_sum', 'loss_sum', 'avg_trade_duration', 'nb_trades'], inplace=True)
# Returning an array of pairs in order of "expectancy"
return final.values
return df.values
def _find_trades_for_stoploss_range(self, ticker_data, pair, stoploss_range):
buy_column = ticker_data['buy'].values