Edge calculation refactored: removing redundant calculations
This commit is contained in:
parent
8a316aba35
commit
2f6aafe66c
@ -215,15 +215,11 @@ class Edge():
|
|||||||
|
|
||||||
def _process_expectancy(self, results: DataFrame) -> list:
|
def _process_expectancy(self, results: DataFrame) -> list:
|
||||||
"""
|
"""
|
||||||
This is a temporary version of edge positioning calculation.
|
This calculates WinRate, Required Risk Reward, Risk Reward and Expectancy of all pairs
|
||||||
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.
|
|
||||||
The calulation will be done per pair and per strategy.
|
The calulation will be done per pair and per strategy.
|
||||||
"""
|
"""
|
||||||
# Removing pairs having less than min_trades_number
|
# 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)
|
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]
|
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:
|
if results.empty:
|
||||||
return []
|
return []
|
||||||
|
|
||||||
groupby_aggregator = {
|
groupby_aggregator = {
|
||||||
'profit_abs': [
|
'profit_abs': [
|
||||||
winrate,
|
('nb_trades', 'count'), # number of all trades
|
||||||
risk_reward_ratio,
|
('profit_sum', lambda x: x[x > 0].sum()), # cumulative profit of all winning trades
|
||||||
required_risk_reward,
|
('loss_sum', lambda x: abs(x[x < 0].sum())), # cumulative loss of all losing trades
|
||||||
expectancy,
|
('nb_win_trades', lambda x: x[x > 0].count()) # number of winning trades
|
||||||
'count'],
|
],
|
||||||
'trade_duration': ['mean']}
|
'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)
|
groupby_aggregator).reset_index(col_level=1)
|
||||||
|
|
||||||
final.columns = final.columns.droplevel(0)
|
# Dropping level 0 as we don't need it
|
||||||
final = final.sort_values(by=['expectancy', 'stoploss'], ascending=False).groupby(
|
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()
|
'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"
|
# 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):
|
def _find_trades_for_stoploss_range(self, ticker_data, pair, stoploss_range):
|
||||||
buy_column = ticker_data['buy'].values
|
buy_column = ticker_data['buy'].values
|
||||||
|
Loading…
Reference in New Issue
Block a user